Skip to content

Instantly share code, notes, and snippets.

@SebHeuze
Created August 23, 2016 09:18
Show Gist options
  • Select an option

  • Save SebHeuze/e84c4451b9c3d19ce3ad450b00253fe4 to your computer and use it in GitHub Desktop.

Select an option

Save SebHeuze/e84c4451b9c3d19ce3ad450b00253fe4 to your computer and use it in GitHub Desktop.
Correction test rutorrent authentification xmlrpc
#!/bin/sh
# This code is in the public domain.
# This script will check your ruTorrent installation. I make no guarantee that it
# will detect all problems...
#
# It will test the following:
# - RPC mount points are protected (requires password)
# - user1 can't access user2's RPC mount point
# - user1 can access his own RPC mount point
# - No files in rutorrent/conf or rutorrent/share can be accessed
# - Only an authenticated user can access ruTorrent
# - .svn dirs can't be accessed
# - user1 can't execute code (NOTE: only a few tests!)
# The server to test, eg. 192.168.0.123
server=$1
# URL path to ruTorrent dir, usually / or /rutorrent
ruTorrentPath=$2
# A valid ruTorrent user
user1=$3
# The ruTorrent user's password
pass1=$4
# The ruTorrent user's RPC mount point.
user1Rpc=$5
user2=$6
pass2=$7
user2Rpc=$8
protocol=http
port=80
# Set to y to only show errors
onlyErrors=y
numFailures=0
numTests=0
echo=echo
$echo -n "x" | grep -qE '^-n' && echo=/bin/echo
error() {
$echo "$@" >&2
}
msg() {
$echo "$@"
}
failed() {
numFailures=$(expr $numFailures + 1)
numTests=$(expr $numTests + 1)
[ $onlyErrors = y ] && _status "$url"
msg
msg " FAILED: $1"
}
passed() {
numTests=$(expr $numTests + 1)
[ $onlyErrors = y ] && return
msg "PASSED"
}
_status() {
$echo -n "Testing $1 ... "
}
status() {
url="$protocol://$1"
[ $onlyErrors = y ] && return
_status "$url"
}
dlFail() {
status $1
curl -k -f $protocol://$1 >/dev/null 2>&1 && failed "DL: $2" || passed
}
dlOk() {
status $1
curl -k -f $protocol://$1 >/dev/null 2>&1 && passed || failed "DL: $2"
}
rpcExec() {
local userInput="$1"
shift
local passwordInput="$1"
shift
local url="$1"
shift
xmlrpc -u $userInput -p $passwordInput -curlnoverifypeer true -curlnoverifyhost true -- $protocol://$url "$@"
}
rpcGetString() {
rpcExec "$@" 2>/dev/null | grep -E '^String:' | head -n1 | sed -e "s/^String: '\\(.*\\)'.*/\\1/"
}
rpcGetNumArrayItems() {
rpcExec "$@" 2>/dev/null | grep -E '^Array of' | head -n1 | sed -e "s/^Array of \\([0-9]*\\) items:\$/\\1/"
}
rpcCmdFail() {
local msg="$1"
shift
status $3
rpcExec "$@" >/dev/null 2>&1 && failed "XMLRPC: $msg" || passed
}
rpcCmdOk() {
local msg="$1"
shift
status $3
rpcExec "$@" >/dev/null 2>&1 && passed || failed "XMLRPC: $msg"
}
rpcFail() {
status $3
rpcExec $1 $2 $3 system.methodHelp system.listMethods >/dev/null 2>&1 && failed "XMLRPC: $2" || passed
}
rpcOk() {
status $3
rpcExec $1 $2 $3 system.methodHelp system.listMethods >/dev/null 2>&1 && passed || failed "XMLRPC: $2"
}
if [ -z "$server" ] || [ -z "$ruTorrentPath" ] || [ -z "$user1" ] || [ -z "$pass1" ] || [ -z "$user1Rpc" ]; then
cat >&2 << EOF
Usage:
$0 server ruTorrentPath user1 pass1 user1Rpc [user2 pass2 user2Rpc]
eg.
$0 192.168.0.123 /rutorrent tom password /RPC2 jerry password /RPC3
$0 192.168.0.123 /rutorrent tom password /RPC2
server = The server to test
ruTorrentPath = URL path of ruTorrent, eg. / or /rutorrent
user1 = A valid ruTorrent user
pass1 = The user's ruTorrent password
user1Rpc = The user's RPC mount, eg. /RPC2
user2 = A valid ruTorrent user
pass2 = The user's ruTorrent password
user2Rpc = The user's RPC mount, eg. /RPC3
EOF
exit 1
fi
ruTorrentPath=${ruTorrentPath%*/}
user1Rpc=${user1Rpc#/}
user2Rpc=${user2Rpc#/}
webserver=$(curl -k -D - $protocol://$server:$port/ 2>/dev/null | grep -iE '^Server:' | sed -e 's/^[^:]*:[ ]*\(.*\)$/\1/')
msg "Server: $server"
msg "Web server: $webserver"
if [ -z "$webserver" ]; then
error "Web server seems to be down! Can't continue."
exit 1
fi
if ! which curl >/dev/null || ! which xmlrpc >/dev/null; then
error "Could not find curl and/or xmlrpc."
exit 1
fi
rtorrentVer=$(rpcGetString $user1 $pass1 $server:$port/$user1Rpc system.client_version)
libtorrentVer=$(rpcGetString $user1 $pass1 $server:$port/$user1Rpc system.library_version)
if [ -z "$rtorrentVer" ] && [ -z "$libtorrentVer" ]; then
error "Could not detect rtorrent version. Is it running?"
exit 1
fi
echo "rtorrent: $rtorrentVer/$libtorrentVer"
rpcFail $server:$port/$user1Rpc "Could access user1's RPC mount without a user + password"
[ -n "$user2" ] && rpcFail $server:$port/$user2Rpc "Could access user2's RPC mount without a user + password"
rpcFail $user1 $pass1 $server:$port/$user2Rpc "Could access user2's RPC mount using user1. #1"
rpcFail $user1 $pass1 $server:$port/$user2Rpc/ "Could access user2's RPC mount using user1. #2"
rpcFail $user1 $pass1 $server:$port/$user2Rpc/asdf "Could access user2's RPC mount using user1. #3"
rpcFail $user1 $pass1 $server:$port/${user2Rpc}randomdata "Could access user2's RPC mount using user1. #4"
rpcOk $user1 $pass1 $server:$port/$user1Rpc "user1 could not access his own RPC mount"
[ -n "$user2" ] && rpcOk $user2 $pass2 $server:$port/$user2Rpc "user2 could not access his own RPC mount"
for cmd in execute execute_capture execute_capture_nothrow execute_nothrow execute_raw execute_raw_nothrow; do
rpcCmdFail "Could execute code ($cmd)" $user1 $pass1 $server:$port/$user1Rpc $cmd sh -c whoami
done
status "$user1 $pass1 $server:$port/$user1Rpc"
if rpcExec $user1 $pass1 $server:$port/$user1Rpc execute sh -c echo 'execute=whoami' '>' '~/testfile}' >/dev/null 2>&1 && \
rpcExec $user1 $pass1 $server:$port/$user1Rpc try_import '~/testfile' >/dev/null 2>&1; then
failed "XMLRPC: Could run commands from file"
else
passed
fi
rpcCmdOk "Could not create a function" $user1 $pass1 $server:$port/$user1Rpc system.method.insert my.func$$ simple 'execute=whoami'
rpcCmdFail "Could execute code using the created func" $user1 $pass1 $server:$port/$user1Rpc my.func$$ ""
for prefix in "" "$user1:$pass1@"; do
dlFail $prefix$server:$port$ruTorrentPath/conf/access.ini "Could access a conf/* file."
dlFail $prefix$server:$port$ruTorrentPath/conf/config.php "Could access a conf/* file."
dlFail $prefix$server:$port$ruTorrentPath/conf/plugins.ini "Could access a conf/* file."
dlFail $prefix$server:$port$ruTorrentPath/conf/users/$user1/config.php "Could access a conf/* file."
dlFail $prefix$server:$port$ruTorrentPath/share/users/$user1/settings/cpu.dat "Could access a conf/* file."
dlFail $prefix$server:$port$ruTorrentPath/conf/.htaccess "Could access conf/.htaccess"
dlFail $prefix$server:$port$ruTorrentPath/share/.htaccess "Could access share/.htaccess"
for u in $user1 $user2; do
dlFail $prefix$server:$port$ruTorrentPath/share/users/$u/settings/cpu.dat "Could access one of $u's share/* files."
dlFail $prefix$server:$port$ruTorrentPath/share/users/$u/settings/extsearch.dat "Could access one of $u's share/* files."
dlFail $prefix$server:$port$ruTorrentPath/share/users/$u/settings/loginmgr.dat "Could access one of $u's share/* files."
dlFail $prefix$server:$port$ruTorrentPath/share/users/$u/settings/rtorrent.dat "Could access one of $u's share/* files."
dlFail $prefix$server:$port$ruTorrentPath/share/users/$u/settings/scheduler.dat "Could access one of $u's share/* files."
dlFail $prefix$server:$port$ruTorrentPath/share/users/$u/settings/uisettings.json "Could access one of $u's share/* files."
dlFail $prefix$server:$port$ruTorrentPath/share/users/$u/settings/rss/cache/info "Could access one of $u's share/* files."
done
dlFail $prefix$server:$port$ruTorrentPath/.svn/entries "Could read .svn subdir"
dlFail $prefix$server:$port$ruTorrentPath/conf/.svn/entries "Could read .svn subdir"
dlFail $prefix$server:$port$ruTorrentPath/css/.svn/entries "Could read .svn subdir"
dlFail $prefix$server:$port$ruTorrentPath/images/.svn/entries "Could read .svn subdir"
dlFail $prefix$server:$port$ruTorrentPath/js/.svn/entries "Could read .svn subdir"
dlFail $prefix$server:$port$ruTorrentPath/lang/.svn/entries "Could read .svn subdir"
dlFail $prefix$server:$port$ruTorrentPath/php/.svn/entries "Could read .svn subdir"
dlFail $prefix$server:$port$ruTorrentPath/plugins/.svn/entries "Could read .svn subdir"
dlFail $prefix$server:$port$ruTorrentPath/share/.svn/entries "Could read .svn subdir"
done
dlFail $server:$port$ruTorrentPath/php/getplugins.php "Could access the site without a password"
dlFail $server:$port$ruTorrentPath/index.html "Could access the site without a password"
dlFail $server:$port$ruTorrentPath/ "Could access the site without a password"
dlFail $server:$port/index.html "Could access the site without a password"
dlFail $server:$port/ "Could access the site without a password"
dlFail baduser:badpassword@$server:$port$ruTorrentPath/index.html "Could access the site with a bad user name + password"
dlOk $user1:$pass1@$server:$port$ruTorrentPath/ "Could not access the ruTorrent site with valid user + password"
dlOk $user1:$pass1@$server:$port$ruTorrentPath/index.html "Could not access the ruTorrent site with valid user + password"
dlOk $user1:$pass1@$server:$port$ruTorrentPath/js/webui.js "Could not access the ruTorrent site with valid user + password"
if [ $numFailures -eq 0 ]; then
msg "All $numTests tests passed!"
msg " Just because all tests passed doesn't mean your server is secure!"
msg " Only a few things were tested."
else
error "$numFailures of $numTests tests failed!"
fi
exit $numFailures
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment