[C#] C# 与 Nessus 交互,动态构建任务计划

C# 与 Nessus 交互,动态构建任务计划

什么是 Nessus?

  它是一个流行的漏洞扫描程序,我们可以通过它来提高自己服务器的安全性。

  本文并不是一篇关于 Nessus 的安装介绍。

  本文演示如何通过 C# 编码通过 HTTP 的 Resful 风格来执行 GET、PUT、POST 和 DELETE 等操作,来实现登录后动态的创建扫描任务和获取执行结果等一系列步骤,而不是通过人为机械的点击按钮来一步步进行操作。

  我先新建一个用于后续 HTTP 请求的的类 HttpRequestMethod.cs:

    /// <summary>
    /// HTTP 请求方法
    /// </summary>
    public class HttpRequestMethod
    {
        public const string Get = "GET";

        public const string Post = "POST";

        public const string Put = "PUT";

        public const string Delete = "DELETE";
    }

  在服务器安装完毕 Nessus 后,输入域名(https://www.nidie.com.cn:8834/)【8834 端口是默认 Nessus 设置的端口】,显示的是一个授权登录页,显然,想要进一步操作必须先通过认证。

  为此,我编写了一个存储会话状态的类 NessusSession.cs

   /// <summary>
    /// 会话
    /// </summary>
    public class NessusSession : IDisposable
    {
        /// <summary>
        /// 端口
        /// </summary>
        public int Port { get; set; }

        /// <summary>
        /// 主机
        /// </summary>
        public string Host { get; set; }

        /// <summary>
        /// 令牌
        /// </summary>
        public string Token { get; private set; }

        /// <summary>
        /// 认证标识
        /// </summary>
        public bool IsAuthenticated { get; private set; }

        #region ctor

        public NessusSession()
        {
            ServicePointManager.ServerCertificateValidationCallback = (object obj, X509Certificate certificate,
                X509Chain chain, SslPolicyErrors errors) => true;
        }

        public NessusSession(string host, int port = 8834) : this()
        {
            Host = host;
            Port = port;
        }

        #endregion ctor

        /// <summary>
        /// 认证
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public bool Authenticate(string userName, string password)
        {
            var obj = new JObject
            {
                ["username"] = userName,
                ["password"] = password
            };

            var result = MakeRequest(HttpRequestMethod.Post, "session", obj);

            if (result == null || result.token == null)
            {
                return false;
            }

            Token = result.token;
            return IsAuthenticated = true;
        }

        /// <summary>
        /// 请求
        /// </summary>
        /// <param name="method"></param>
        /// <param name="uri"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public dynamic MakeRequest(string method, string uri, JObject data = null)
        {
            var url = $"https://{Host}:{Port}/{uri}";
            var request = WebRequest.Create(url);
            request.Method = method;

            if (!Token.IsNullOrEmpty())
            {
                request.Headers["X-Cookie"] = $"token={Token}";
            }

            request.ContentType = "application/json";

            if (data == null)
            {
                request.ContentLength = 0;
            }
            else
            {
                var bytes = Encoding.UTF8.GetBytes(data.ToString());
                request.ContentLength = bytes.Length;

                using (var rs = request.GetRequestStream())
                {
                    rs.Write(bytes, 0, bytes.Length);
                }
            }

            var respStream = request.GetResponse().GetResponseStream();

            if (respStream == null)
            {
                return null;
            }

            string response;

            using (var reader = new StreamReader(respStream))
            {
                response = reader.ReadToEnd();
            }

            return response.IsNullOrEmpty() ? null : response.ToJson();
        }

        /// <summary>
        /// 注销
        /// </summary>
        public void LogOut()
        {
            if (!IsAuthenticated) return;

            MakeRequest(HttpRequestMethod.Delete, "session");
            IsAuthenticated = false;
        }


        public void Dispose()
        {
            LogOut();
        }
    }

  其中,Authenticate() 方法的主要目的是通过登录验证获取 token 并保存,MakeRequest() 方法是对我们后续进行 HTTP 请求的代码封装(在认证成功后每次请求会携带对应的 token 值进行后续操作,因为我们是通过 json 方式进行值传递,所以需要设置“application/json” ),LogOut() 方法是注销操作,采用 DELETE 的方式。

  不知道大家有没有注意到 url 的地址头是 https,所以我在构造函数中设置了验证服务器证书的回调(ServicePointManager.ServerCertificateValidationCallback = (object obj, X509Certificate certificate,X509Chain chain, SslPolicyErrors errors) => true;)。

  现在,需要编写一个测试类运行,观察编写的方法是否生效,即验证是否登录成功。

        [TestMethod]
        public void NessusSessionTest()
        {
            using (var session = new NessusSession("www.nidie.com.cn"))
            {
                var result = session.Authenticate("admin", "you guess");

                if (!result)
                {
                    throw new Exception("认证失败");
                }

                Console.WriteLine(session.Token);
            }
        }

  从测试的结果来看,毫无疑问,事实是经得起考验的。

  接下来,登录后我们需要进行的就是构建一系列扫描活动流程操作,为此我编写了一个类 NessusManager.cs,它包含了我接下来需要介绍的操作,类似 Facede 模式。

   public class NessusManager : IDisposable
    {
        private readonly NessusSession _session;

        public NessusManager(NessusSession session)
        {
            _session = session;
        }

        /// <summary>
        /// 获取扫描策略
        /// </summary>
        /// <returns></returns>
        public dynamic GetScanPolicies()
        {
            return _session.MakeRequest(HttpRequestMethod.Get, "editor/policy/templates");
        }

        /// <summary>
        /// 创建扫描任务
        /// </summary>
        /// <param name="policyId"></param>
        /// <param name="targets"></param>
        /// <param name="name"></param>
        /// <param name="description"></param>
        /// <returns></returns>
        public dynamic CreateScanJob(string policyId, string targets, string name, string description)
        {
            var data = new JObject
            {
                ["uuid"] = policyId,
                ["settings"] = new JObject
                {
                    ["name"] = name,
                    ["text_targets"] = targets,
                    ["description"] = description
                }
            };

            return _session.MakeRequest(HttpRequestMethod.Post, "scans", data);
        }

        /// <summary>
        /// 开始扫描
        /// </summary>
        /// <param name="scanId"></param>
        /// <returns></returns>
        public dynamic StartScan(int scanId)
        {
            return _session.MakeRequest(HttpRequestMethod.Post, $"scans/{scanId}/launch");
        }

        /// <summary>
        /// 获取扫描结果
        /// </summary>
        /// <param name="scanId"></param>
        /// <returns></returns>
        public dynamic GetScanResult(int scanId)
        {
            return _session.MakeRequest(HttpRequestMethod.Get, $"scans/{scanId}");
        }


        public void Dispose()
        {
            _session?.Dispose();
        }
    }

猜你喜欢

转载自www.cnblogs.com/liqingwen/p/9201834.html
今日推荐