docs(site): complete the command builder — features, options, client-… #51
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: ['**'] | |
| pull_request: | |
| jobs: | |
| test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Set up PHP | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: '8.3' | |
| extensions: pdo_sqlite, curl | |
| - name: Install pytest | |
| run: pip install pytest | |
| - name: Run the offline + runtime test suite | |
| # Unit tests, generation matrix, and full runtime E2E (php -S + | |
| # protocol client): login, exec, cd, transports, optional features, | |
| # fetch module (both HTTP paths), sql console (PDO sqlite). | |
| run: python -m pytest tests/ -q | |
| - name: Generate shells (all themes + option combinations) | |
| run: | | |
| python3 p0wnyShellX.py -p "CITestPass42!" -o /tmp/s1.php | |
| python3 p0wnyShellX.py -p "CITestPass42!" -t matrix -j 5 -o /tmp/s2.php | |
| python3 p0wnyShellX.py -p "CITestPass42!" -t corporate-blue --no-junk -o /tmp/s3.php | |
| python3 p0wnyShellX.py -p "CITestPass42!" -t infra-dark -j 80 -u operator -o /tmp/s4.php | |
| python3 p0wnyShellX.py -p "CITestPass42!" --seed 1337 -o /tmp/s5.php | |
| python3 p0wnyShellX.py -p "CITestPass42!" --transport mimic -o /tmp/s6.php | |
| python3 p0wnyShellX.py -p "CITestPass42!" --transport rc4 -o /tmp/s7.php | |
| python3 p0wnyShellX.py -p "CITestPass42!" -t none -o /tmp/s8.php | |
| python3 p0wnyShellX.py -p "CITestPass42!" -t poly -o /tmp/s9.php | |
| python3 p0wnyShellX.py -p "CITestPass42!" --revshell --clearlog --portscan --no-junk -o /tmp/s10.php | |
| python3 p0wnyShellX.py -p "CITestPass42!" --sql --fetch --no-junk -o /tmp/s11.php | |
| - name: PHP syntax check | |
| run: | | |
| for f in /tmp/s1.php /tmp/s2.php /tmp/s3.php /tmp/s4.php /tmp/s5.php /tmp/s6.php /tmp/s7.php /tmp/s8.php /tmp/s9.php /tmp/s10.php /tmp/s11.php; do | |
| php -l "$f" || exit 1 | |
| done | |
| - name: Check no static signatures present | |
| run: | | |
| SIGNATURES=( | |
| "fetchContentBlock" | |
| "_resolveTask" | |
| "SESSION_ACTIVE" | |
| "feature=shell" | |
| "pipeCall-cmd" | |
| "panel-stream" | |
| "getPassword" | |
| "suggestEntry" | |
| "featurePwd" | |
| ) | |
| for f in /tmp/s1.php /tmp/s2.php /tmp/s3.php /tmp/s4.php /tmp/s5.php /tmp/s6.php /tmp/s7.php /tmp/s8.php /tmp/s9.php /tmp/s10.php; do | |
| for sig in "${SIGNATURES[@]}"; do | |
| if grep -q "$sig" "$f"; then | |
| echo "FAIL: static signature '$sig' found in $f" | |
| exit 1 | |
| fi | |
| done | |
| done | |
| echo "All static signature checks passed." | |
| - name: Verify polymorphism (two runs must differ) | |
| run: | | |
| python3 p0wnyShellX.py -p "CITestPass42!" -o /tmp/poly_a.php 2>/dev/null | |
| python3 p0wnyShellX.py -p "CITestPass42!" -o /tmp/poly_b.php 2>/dev/null | |
| if diff -q /tmp/poly_a.php /tmp/poly_b.php > /dev/null 2>&1; then | |
| echo "FAIL: two consecutive runs produced identical output." | |
| exit 1 | |
| fi | |
| echo "Polymorphism verified." | |
| - name: Verify seed reproducibility (same seed must produce same output) | |
| run: | | |
| python3 p0wnyShellX.py -p "CITestPass42!" --seed 9999 -o /tmp/seed_a.php 2>/dev/null | |
| python3 p0wnyShellX.py -p "CITestPass42!" --seed 9999 -o /tmp/seed_b.php 2>/dev/null | |
| diff /tmp/seed_a.php /tmp/seed_b.php || (echo "FAIL: same seed produced different output." && exit 1) | |
| echo "Seed reproducibility verified." | |
| - name: Verify exec fallback chain integrity | |
| run: | | |
| for f in /tmp/s1.php /tmp/s2.php /tmp/s3.php /tmp/s4.php /tmp/s5.php /tmp/s8.php /tmp/s9.php /tmp/s10.php; do | |
| # Core methods must always be present | |
| for method in exec shell_exec; do | |
| if ! grep -q "function_exists('${method}')" "$f"; then | |
| echo "FAIL: core method '${method}' missing in $f" | |
| exit 1 | |
| fi | |
| done | |
| if ! grep -q "'system'" "$f"; then | |
| echo "FAIL: core method 'system' missing in $f" | |
| exit 1 | |
| fi | |
| # At least one optional method must survive | |
| found=0 | |
| for method in passthru popen proc_open; do | |
| grep -q "'${method}'" "$f" && found=1 | |
| done | |
| if [ $found -eq 0 ]; then | |
| echo "FAIL: no optional exec method present in $f" | |
| exit 1 | |
| fi | |
| done | |
| echo "Exec fallback chain integrity verified." | |
| - name: Verify mimic transport (param names must not be cmd/cwd) | |
| run: | | |
| for param in cmd cwd filename type path file; do | |
| if grep -q "POST\['${param}'\]" /tmp/s6.php; then | |
| echo "FAIL: plain param name '${param}' found in mimic shell" | |
| exit 1 | |
| fi | |
| done | |
| echo "Mimic transport: no plain param names found." | |
| - name: Verify rc4 transport (tEnc/tDec must be present, no plain params) | |
| run: | | |
| if ! grep -q "function tEnc" /tmp/s7.php; then | |
| echo "FAIL: tEnc not found in rc4 shell" | |
| exit 1 | |
| fi | |
| for param in cmd cwd filename type path file; do | |
| if grep -q "POST\['${param}'\]" /tmp/s7.php; then | |
| echo "FAIL: plain param name '${param}' found in rc4 shell" | |
| exit 1 | |
| fi | |
| done | |
| echo "RC4 transport: tEnc present, no plain param names." | |
| - name: Verify switch case counts | |
| run: | | |
| # Default builds (no --revshell/--clearlog/--portscan) must have exactly 4 cases | |
| for f in /tmp/s1.php /tmp/s2.php /tmp/s3.php /tmp/s4.php /tmp/s5.php /tmp/s6.php /tmp/s7.php /tmp/s8.php /tmp/s9.php; do | |
| count=$(grep -c "case '" "$f" || true) | |
| if [ "$count" -ne 4 ]; then | |
| echo "FAIL: expected 4 switch cases in $f (default build), got $count" | |
| exit 1 | |
| fi | |
| done | |
| # Full feature build (--revshell --clearlog --portscan) must have exactly 7 cases | |
| count=$(grep -c "case '" /tmp/s10.php || true) | |
| if [ "$count" -ne 7 ]; then | |
| echo "FAIL: expected 7 switch cases in s10.php (full features), got $count" | |
| exit 1 | |
| fi | |
| # sql+fetch build must have exactly 6 cases | |
| count=$(grep -c "case '" /tmp/s11.php || true) | |
| if [ "$count" -ne 6 ]; then | |
| echo "FAIL: expected 6 switch cases in s11.php (--sql --fetch), got $count" | |
| exit 1 | |
| fi | |
| echo "Switch case counts verified (4 default, 7 full-feature, 6 sql+fetch)." | |
| - name: Verify mimic transport excludes new plain param names | |
| run: | | |
| for param in ip port logfile pattern target ports; do | |
| if grep -q "POST\['${param}'\]" /tmp/s6.php; then | |
| echo "FAIL: plain param name '${param}' found in mimic shell" | |
| exit 1 | |
| fi | |
| done | |
| echo "Mimic transport: no new plain param names found." | |
| - name: Verify bcrypt hash is present and valid | |
| run: | | |
| php -r " | |
| \$f = file_get_contents('/tmp/s1.php'); | |
| preg_match('/define\(.*?,\s*\'(\\\$2y\\\$[^\']+)\'\)/m', \$f, \$m); | |
| if (empty(\$m[1])) { echo 'FAIL: bcrypt hash not found\n'; exit(1); } | |
| if (!password_verify('CITestPass42!', \$m[1])) { echo 'FAIL: password_verify returned false\n'; exit(1); } | |
| echo 'Bcrypt verification passed.\n'; | |
| " |