前段时间看到了阿里云发的一篇文章,捕获到了某挖矿软件利用Hadoop Yarn的RPC接口进行执行命令。

上周有空看了下,在java中可以很简单的使用yarnClient调用RPC接口进行通信,其实就是之前的Hadoop Yarn REST API未授权访问漏洞变成,由REST API变成了RPC接口,REST API的默认端口为8088,RPC的默认端口为8032。

整个执行命令的通信过程分为两步 :

这个过程中会发送不少RPC包
  1. 请求APPID
  2. 提交执行任务

在网上找了一个使用yarnClient获取信息的代码(https://blog.csdn.net/jsbylibo/article/details/109286147),

package com.**.dfp.rtsync.task;
 
import lombok.extern.slf4j.Slf4j;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.records.ApplicationReport;
import org.apache.hadoop.yarn.api.records.YarnApplicationState;
import org.apache.hadoop.yarn.client.api.YarnClient;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.exceptions.YarnException;
 
import java.io.IOException;
import java.util.EnumSet;
import java.util.List;
 
/**
 * Description
 *
 * @author Bob
 * @date 2020/10/22
 **/
@Slf4j
public class YarnTest {
    public static void main(String[] args){
        Configuration conf = new YarnConfiguration();
        YarnClient yarnClient = YarnClient.createYarnClient();
        yarnClient.init(conf);
        yarnClient.start();
        try {
            //查询运行状态所有任务
            List<ApplicationReport> applicationReportList = yarnClient.getApplications(EnumSet.of(YarnApplicationState.RUNNING));
            for (ApplicationReport applicationReport : applicationReportList) {
                // 获取Name
                String name = applicationReport.getName();
                // 获取ApplicationType
                String applicationType = applicationReport.getApplicationType();
                ApplicationId applicationId;
                log.info("-----------applicationId:{},name:{},quene:{},user:{},type:{}", applicationReport.getApplicationId(), applicationReport.getName(), applicationReport.getQueue(), applicationReport.getUser(), applicationReport.getApplicationType());
                // 检查是否实时集成任务(Apache Spark)
                if (name.equals(applicationName)) {
                    if ("Apache Spark".equalsIgnoreCase(applicationType) || "Spark".equalsIgnoreCase(applicationType)) {
                        // ApplicationId
                        applicationId = applicationReport.getApplicationId();
                        // Kill applicationId
                        //yarnClient.killApplication(applicationId);
                        log.info("==========applicationId:{} is killed!", applicationName);
                        break;
                    } else {
                        log.warn("The app {} is not valid spark job! ", applicationName);
                    }
                }
            }
        } catch (YarnException | IOException e) {
            log.error("kill killYarnApplication error:", e);
            throw new BusinessException("停止Yarn任务失败!");
        } finally {
            if (yarnClient != null) {
                try {
                    // 停止YarnClient
                    yarnClient.stop();
                    // 关闭YarnClient
                    yarnClient.close();
                } catch (IOException e) {
                    log.error("关闭Yarn Client失败!", e);
                }
            }
        }
    }
}

简单改造后就可以变成执行命令的JAVA代码:

最后修改:2021 年 11 月 22 日
如果觉得我的文章对你有用,请随意赞赏