#!/bin/bash set -e # 脚本中任何命令失败都立即退出 #清屏 clear log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" } print_header() { echo -e "\033[1;33m$1\033[0m" } print_info() { echo -e "\033[1;36m$1\033[0m" } # 确保是 root 用户 if [ "$EUID" -ne 0 ]; then log "请使用 root 权限运行此脚本" exit 1 fi # 确保是 Debian/Ubuntu 系统 if ! grep -qi 'debian\|ubuntu' /etc/os-release 2>/dev/null; then log "此脚本仅支持 Debian/Ubuntu 系统" exit 1 fi # 更新系统 log "更新系统" if apt update ; then log "系统更新完成" else log "系统更新失败" exit 1 fi #安装基本工具 log "安装基本工具" if apt install net-tools ufw -y ; then log "基本工具安装完成" else log "基本工具安装失败" exit 1 fi log "清理APT缓存" if apt clean ; then log "APT缓存清理完成" else log "APT缓存清理失败" exit 1 fi log "预准备完成" # 函数定义 check_command() { local cmd="$1" if ! command -v "$cmd" >/dev/null 2>&1; then log "错误:未找到命令 $cmd" exit 1 fi } backup_config() { local config_file="$1" if [ -f "$config_file" ]; then if [ ! -f "${config_file}.bak" ]; then log "备份文件不存在,将创建备份文件: ${config_file}.bak" else log "备份文件已存在,将覆盖备份文件: ${config_file}.bak" fi else log "警告:文件 $config_file 不存在" fi } write_config() { local file="$1" if cat > "$file"; then log "配置写入成功: $file" else log "错误:无法写入文件 $file" exit 1 fi } setup_ssh_key() { local key_type="$1" local ssh_dir="/root/.ssh" mkdir -p "$ssh_dir" chown root:root "$ssh_dir" chmod 700 "$ssh_dir" case $key_type in "generate") local ssh_key_file="$ssh_dir/id_rsa" if ssh-keygen -t rsa -b 4096 -f "$ssh_key_file" -N "" &>/dev/null; then log "SSH 密钥已生成" else log "SSH 密钥生成失败" return 1 fi touch "$ssh_dir/authorized_keys" chmod 600 "$ssh_dir/authorized_keys" if cat "${ssh_key_file}.pub" >> "$ssh_dir/authorized_keys"; then log "公钥添加成功" if [[ $pubkey =~ ^ssh-rsa ]]; then if echo "$pubkey" >> "$ssh_dir/authorized_keys"; then log "公钥已添加" else log "错误:无效的公钥格式" return 1 fi else log "错误:无效的公钥格式" return 1 fi log "公钥添加失败" return 1 fi local temp_key_file temp_key_file=$(mktemp) if cat "$ssh_key_file" > "$temp_key_file" && chmod 600 "$temp_key_file"; then log "私钥保存在: ${temp_key_file}" else log "私钥保存失败" rm -f "$temp_key_file" return 1 fi ;; "import") read -r -p "请输入 SSH 公钥: " pubkey if [[ $pubkey =~ ^ssh-rsa ]]; then if echo "$pubkey" >> "$ssh_dir/authorized_keys"; then log "公钥已添加" else log "错误:无法添加公钥" return 1 fi else log "错误:无效的公钥格式" return 1 fi ;; *) log "未知的 key_type: $key_type" return 1 ;; esac } check_installed() { local component="$1" log "检查 $component 是否已安装..." command -v "$component" &>/dev/null && log "$component 已安装,跳过配置" && return 0 return 1 } get_python_version() { python3 -c 'import sys; print(".".join(map(str, sys.version_info[:2])))' } check_ufw_rule() { local port="$1" local comment="$2" if ufw status | grep -qE "^($port(/tcp)?|$port(/tcp)? \(v6\))\s+ALLOW"; then if [ -n "$comment" ] && ufw status | grep -E "^$port(/tcp)?\s+.*#.*$comment" >/dev/null; then log "端口 $port 已配置 ($comment)" else log "端口 $port 已存在其他规则" fi return 0 fi return 1 } backup_with_timestamp() { local file="$1" local max_backups="${2:-3}" local backup_dir backup_dir=$(dirname "$file") local backup_file backup_file="${file}.$(date +%Y%m%d_%H%M%S).bak" if cp "$file" "$backup_file"; then log "备份成功: $backup_file" else log "错误:无法创建备份文件 $backup_file" return 1 fi mapfile -t old_backups < <(find "$backup_dir" -name "$(basename "${file}")*.bak" -type f -printf '%T+ %p\n' | sort -r | cut -d' ' -f2-) while [ "${#old_backups[@]}" -gt "$max_backups" ]; do if rm -f "${old_backups[-1]}"; then log "删除旧备份文件: ${old_backups[-1]}" else log "错误:无法删除旧备份文件 ${old_backups[-1]}" return 1 fi unset 'old_backups[-1]' done } update_sources() { local os_version if [ -f /etc/debian_version ]; then os_version=$(cat /etc/debian_version) case $os_version in 10*) log "检测到 Debian 10 (Buster),更新软件源..." cp /etc/apt/sources.list "/etc/apt/sources.list.backup.$(date +%Y%m%d)" cat > /etc/apt/sources.list < /etc/timezone dpkg-reconfigure -f noninteractive tzdata log "时区已设置为上海" else log "警告:无法找到上海时区文件" fi check_python_version() { local current_version current_version=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null) || { log "错误:无法解析 Python 版本号"; exit 1; } local required_major=3 local required_minor=9 local current_major local current_minor current_major=$(echo "$current_version" | cut -d. -f1) current_minor=$(echo "$current_version" | cut -d. -f2) if [ "$current_major" -gt "$required_major" ] || { [ "$current_major" -eq "$required_major" ] && [ "$current_minor" -ge "$required_minor" ]; }; then log "当前 Python 版本 ($current_version) 满足要求" return 0 else log "当前 Python 版本 ($current_version) 当前版本过低(3.9+ required)" return 1 fi } upgrade_python() { local os_id local os_version # 定义一个通用的日志函数,增强日志信息的上下文 log() { local message="$1" local script_name="${0##*/}" # 获取当前脚本名称 echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$script_name] $message" >&2 } # 检查文件是否存在且可读 check_file_readable() { local file="$1" if [[ ! -f "$file" ]]; then log "错误:文件 '$file' 不存在" return 1 elif [[ ! -r "$file" ]]; then log "错误:文件 '$file' 不可读" return 1 fi return 0 } # 主逻辑:加载 /etc/os-release 文件 if ! check_file_readable "/etc/os-release"; then exit 1 fi # 加载文件内容 if [ -f /etc/os-release ]; then #shellcheck disable=SC1091 . /etc/os-release else log "错误:无法找到 /etc/os-release 文件" exit 1 fi # 可选:验证关键字段是否存在(根据实际需求调整) if [[ -z "${NAME+x}" || -z "${VERSION_ID+x}" ]]; then log "错误:/etc/os-release 文件中缺少关键字段 (NAME 或 VERSION_ID)" exit 1 fi os_id=$ID os_version=$VERSION_ID case "$os_id" in "debian") case "$os_version" in "10") echo "deb http://deb.debian.org/debian buster-backports main" > /etc/apt/sources.list.d/backports.list apt update apt -t buster-backports install -y python3.9 python3.9-dev python3.9-venv ;; "11"|"12") apt update apt install -y python3.9 python3.9-dev python3.9-venv ;; esac ;; "ubuntu") add-apt-repository -y ppa:deadsnakes/ppa apt update apt install -y python3.9 python3.9-dev python3.9-venv ;; esac update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.9 1 } fix_python_deps() { log "修复 Python 依赖..." python3 -c "import apt_pkg" 2>/dev/null || { log "重新安装 python3-apt 以修复 apt_pkg 模块..."; apt-get remove --purge -y python3-apt && apt-get install -y python3-apt; } } log "检查 Python 版本要求..." check_python_version || { log "正在升级 Python..."; upgrade_python && check_python_version || { log "Python 版本升级失败"; exit 1; } && log "Python 已成功升级到 3.9+" && fix_python_deps; } log "检查 fail2ban 状态..." if ! command -v fail2ban-client &>/dev/null; then log "fail2ban 未安装,开始安装..." if ! apt update || ! apt install -y fail2ban python3-systemd; then log "fail2ban 安装失败" exit 1 fi fi log "配置 fail2ban..." backup_with_timestamp "/etc/fail2ban/jail.local" 3 cat > /etc/fail2ban/jail.local <fail2ban_test.log; then log "fail2ban 配置测试失败,详情请查看 fail2ban_test.log" exit 1 fi # 重启 fail2ban 服务 if ! systemctl restart fail2ban 2>fail2ban_restart.log; then log "fail2ban 服务重启失败,详情请查看 fail2ban_restart.log" exit 1 fi # 记录成功日志 log "fail2ban 配置完成" log "检查日志清理配置..." CLEANUP_LOG_SCRIPT="/usr/local/bin/cleanup_logs.sh" CRON_SCHEDULE="0 2 * * *" if [ ! -f "$CLEANUP_LOG_SCRIPT" ]; then cat > "$CLEANUP_LOG_SCRIPT" <<'EOFF' #!/bin/bash find /var/log -type f -name "*.log" -mtime +30 -exec rm -f {} \; echo "$(date): Logs older than 30 days have been deleted." >> /var/log/cleanup.log EOFF chmod +x "$CLEANUP_LOG_SCRIPT" crontab -l | grep -q "$CLEANUP_LOG_SCRIPT" || (crontab -l 2>/dev/null; echo "$CRON_SCHEDULE $CLEANUP_LOG_SCRIPT") | crontab - log "日志清理配置完成" else log "日志清理已配置,跳过" fi log "开始安装 Cowrie..." COWRIE_INSTALL_DIR="/opt/cowrie" if [ ! -d "$COWRIE_INSTALL_DIR" ] || [ ! -f "$COWRIE_INSTALL_DIR/bin/cowrie" ]; then log "创建 Cowrie 用户..." id cowrie &>/dev/null || useradd -m -s /bin/bash cowrie || { log "创建 cowrie 用户失败"; exit 1; } log "准备安装目录..." rm -rf "$COWRIE_INSTALL_DIR" mkdir -p "$COWRIE_INSTALL_DIR" log "克隆 Cowrie 仓库..." git clone https://github.com/cowrie/cowrie.git "$COWRIE_INSTALL_DIR" || { log "克隆 Cowrie 仓库失败"; exit 1; } log "初始化 Python 环境..." cd "$COWRIE_INSTALL_DIR" python3 -m virtualenv cowrie-env || { log "创建虚拟环境失败"; exit 1; } #shellcheck disable=SC1091 . "$COWRIE_INSTALL_DIR/cowrie-env/bin/activate" pip install --upgrade pip pip install -r requirements.txt || { log "安装依赖失败"; exit 1; } deactivate log "配置 Cowrie..." cp etc/cowrie.cfg.dist etc/cowrie.cfg sed -i 's/hostname = svr04/hostname = debian-s31343/' etc/cowrie.cfg sed -i 's/^#listen_port=2222/listen_port=2222/' etc/cowrie.cfg sed -i 's/^#download_limit_size=10485760/download_limit_size=1048576/' etc/cowrie.cfg mkdir -p var/log/cowrie chown -R cowrie:cowrie "$COWRIE_INSTALL_DIR" chmod -R 755 "$COWRIE_INSTALL_DIR" chmod 700 "$COWRIE_INSTALL_DIR/var/log/cowrie" log "Cowrie 基础安装完成" fi log "配置 Cowrie 服务..." PYTHON_VERSION=$(get_python_version) cat < /etc/systemd/system/cowrie.service [Unit] Description=Cowrie SSH Honeypot After=network.target [Service] Type=simple User=cowrie Group=cowrie WorkingDirectory=$COWRIE_INSTALL_DIR Environment="PYTHONPATH=$COWRIE_INSTALL_DIR/cowrie-env/lib/python${PYTHON_VERSION}/site-packages" Environment="PATH=$COWRIE_INSTALL_DIR/cowrie-env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ExecStart=/bin/bash -c 'cd $COWRIE_INSTALL_DIR && source cowrie-env/bin/activate && bin/cowrie start -n' Restart=always RestartSec=30 [Install] WantedBy=multi-user.target EOF #启动Cowrie服务 log "启动 Cowrie 服务..." if systemctl daemon-reload && systemctl enable cowrie && systemctl start cowrie then log "Cowrie 服务已启动" else log "启动 Cowrie 服务失败" exit 1 fi log "检查服务状态..." check_service() { local service_name="$1" log "检查 $service_name 服务状态..." if systemctl is-active --quiet "$service_name"; then log "$service_name 服务运行正常" else log "$service_name 服务未运行" return 1 fi } check_service "cowrie" check_service "fail2ban" print_header "重要提示" log "1. 请确保记录以下信息:" print_info "SSH 端口: $FINAL_SSH_PORT" [ -n "$TEMP_KEY_FILE" ] && print_info "SSH 私钥位置: $TEMP_KEY_FILE" echo "2. 确保防火墙规则正确配置" echo "3. 测试新的 SSH 配置前不要关闭当前会话" print_header "常用命令" echo "查看服务状态:" print_info "systemctl status cowrie" print_info "systemctl status fail2ban" print_info "ufw status" echo "查看日志:" print_info "tail -f $COWRIE_INSTALL_DIR/var/log/cowrie/cowrie.log" print_info "journalctl -u cowrie -f" print_info "tail -f /var/log/fail2ban.log" echo -e "\n\033[1;32m安装完成!如需帮助,请访问项目主页。\033[0m\n" log "所有操作成功完成!"