DEV Community

HimitsuShell
HimitsuShell

Posted on • Originally published at Medium

ssc Security Analysis: Structural Limitations of a Shell Script Compiler

ssc is a project designed to improve upon shc, a popular Shell Script Compiler. Like shc, it converts shell scripts into C source code and then builds them into binaries to prevent source code exposure.

GitHub logo liberize / ssc

Convert shell script to binary

Simple Script Compiler

中文版

This is a powerful tool to turn almost any script to binary, inspired by shc.

ssc itself is not a compiler such as cc, it rather generates c++ source code with script code, then uses c++ compiler to compile the source into a binary which behaves exactly like the original script.

Upon execution, the binary will call real script interpreter (systemwide, bundled or embeded), and fork a child process to pipe script code to the interpreter to execute.

Prerequisite

(Note: g++ version should be 5.2 or above)

For Debian-based Linux distros
  • g++, perl, binutils
  • libc-dev, libstdc++-dev (only required by -s flag)
  • libz-dev (only required by -E flag)
  • libz-dev, libfuse-dev, git, gcc, make, automake, autoconf, pkg-config, libtool, squashfs-tools (only required by -M flag)

For RedHat-based Linux distros
  • g++, perl, binutils
  • glibc-static, libstdc++-static (only required by -s flag)
  • zlib-devel (only required by -E flag)
  • zlib-devel, fuse-devel, git, gcc…

Unlike shc, ssc does not directly depend on the system shell. Instead, it embeds a shell interpreter inside the generated binary.

As a result, the attack technique demonstrated in the previous shc analysis using auditd (an operating system-level monitoring tool) cannot be applied to ssc in the same way.

However, ssc also has its own structural limitations.

Binaries generated by ssc temporarily extract an embedded shell interpreter (for example, BusyBox) to a path such as: /tmp/ssc.XXXXXX/busybox

The shell script is then passed to the extracted interpreter for execution.

As a result, if an attacker monitors the moment the embedded interpreter becomes externally accessible, the original shell script can be recovered.

scheme

Let’s reproduce the issue and examine the limitation in practice.


Test Environment

On Ubuntu 24.04, use the following shell script.

shell_script

Use the following command to embed the shell interpreter

./ssc test ssc_binary -s -r -e busybox -c
Enter fullscreen mode Exit fullscreen mode

Reproducing the Issue

# Install bpftrace
sudo apt install bpftrace

# Start monitoring in Terminal 1
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_write /comm == "ssc_binary"/ { printf("PID: %d | FD: %d | Data: %s\n", pid, args->fd, str(args->buf)); }'

# Run ssc_binary in Terminal 2
./ssc_binary
Enter fullscreen mode Exit fullscreen mode

As shown in the screenshot below, the original shell script can be recovered using bpftrace, a kernel-level monitoring tool.

Terminal2

Terminal1


Mitigation

To avoid this issue, a Shell Script Compiler should process the shell interpreter internally without extracting it outside the binary.

Architectures that temporarily expose the interpreter to the operating system may still be vulnerable to kernel-level monitoring attacks such as the one demonstrated above.

One example of an alternative approach is HimitsuShell.

The following articles provide additional information:

Top comments (0)