xml地图|网站地图|网站标签 [设为首页] [加入收藏]
动态构建扫描任务计划,用法和原理
分类:编程

/*

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

一、前言

 Swift不允许隐式类型转换, 但可以使用显示类型转换(强制类型转换)

目录

  • 什么是 Nessus?
  • 创建会话类 NessusSession
  • 登录测试
  • 创建操作类 NessusManager
  • 操作测试

 

Python 面向对象中有继承这个概念,初学时感觉很牛逼,里面也有个super类,经常见到,最近做一些题才算是理解了。特地记录分享给后来研究的小伙伴,毕竟现在小学生都开始学了(滑稽脸)

 OC:

什么是 Nessus?

  它是一个流行的漏洞扫描程序,我们可以通过它来提高自己服务器的安全性;定期对服务器进行漏洞和补丁扫描,使用已知漏洞的数据库评估正在运行在网络上不同平台的系统,这可以帮助我们更快速的识别风险以及进行合理规避。针对个人来讲,它是免费的。

 

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

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

 

二、代码

 int intValue = 10;

创建会话类 NessusSession

  在服务器安装完毕 Nessus 后,输入地址(本文演示时使用的是 )【8834 端口是默认 Nessus 设置的端口】,显示的是一个授权登录页,显然,想要进一步操作必须先通过认证。

图片 1

 

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

图片 2图片 3

    /// <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}";
            }

            //set: json
            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);
                }
            }

            //request --> response
            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();
        }
    }

NessusSession

 

  代码分析:

  其中,Authenticate(userName, password) 方法的主要目的是通过登录验证,请求时通过 Jobject 对象将参数进行包装传输,在成功后将获取的 token 值(又称身份令牌)进行保存,方便后续操作。

        /// <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;
        }

 

  因为所有的方法调用都是以 HTTP 方式进行请求,所以封装了方法 MakeRequest(string method, string uri, JObject data = null) 。在登录成功后,每次请求都会携带对应的 token 值(request.Headers["X-Cookie"] = $"token={Token}"),我们在进行参数传递的时候都是以 json 的格式进行传输,所以需要设置 request.ContentType = "application/json",为了方便后续返回值的直接使用,我使用了 dynamic 类型作为返回值,这样也可以减少创建多个实体类。

        /// <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}";
            }

            //set: json
            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);
                }
            }

            //request --> response
            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();
        }

 

  同时,我新建一个类 HttpRequestMethod.cs 来保存 HTTP 请求方式:

    /// <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";
    }

 

  LogOut() 是注销操作,采取的是 DELETE 方式。因为我希望在关闭时直接释放,所以继承了 IDisposable 接口并实现。

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

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

        public void Dispose()
        {
            LogOut();
        }

 

  还有一个比较特殊的地方,因为 url 的地址头是 https,所以我在构造函数中直接设置了验证服务器证书的回调为 true,来保证 SSL 证书的正常接受,即 ServicePointManager.ServerCertificateValidationCallback = (object obj, X509Certificate certificate,X509Chain chain, SslPolicyErrors errors) => true。

        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;
        }

 

直接上干货,能把下面一个问题全答对,后面就不用看了。

 double doubleValue = (double)intValue;

登录测试

  现在,我已经实现了会话类 NessusSession,需要编写一个测试类运行,传入 IP 或域名,以及对应的用户名和密码,因为实现了 IDisposable 接口,所以可以直接使用 using 进行释放,观察编写的方法是否生效,即验证是否登录成功。因为登录失败根本无法进行后续的操作,所以在登录失败时我直接抛出“认证失败”的异常描述值。

        [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);
            }
        }

 

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

图片 4

 

class A():
    def go(self):
        print ("go A go!")
    def stop(self):
        print ("stop A stop!")
    def pause(self):
        raise Exception("Not Implemented")
class B(A):
    def go(self):
        super(B, self).go()
        print ("go B go!")
class C(A):
    def go(self):
        super(C, self).go()
        print ("go C go!")
    def stop(self):
        super(C, self).stop()
        print ("stop C stop!")
class D(B,C):
    def go(self):
        super(D, self).go()
        print ("go D go!")
    def stop(self):
        super(D, self).stop()
        print ("stop D stop!")
    def pause(self):
        print ("wait D wait!")
class E(B,C):
    pass
a = A()
b = B()
c = C()
d = D()
e = E()
# 说明下列代码的输出结果
a.go()
print('--------')
b.go()
print('--------')
c.go()
print('--------')
d.go()
print('--------')
e.go()
print('--------')
a.stop()
print('--------')
b.stop()
print('--------')
c.stop()
print('--------')
d.stop()
print('--------')
e.stop()
print(D.mro())
a.pause()
b.pause()
c.pause()
d.pause()
e.pause()

 

创建操作类 NessusManager

  这是第二个关键类 NessusManager,它类似 Facede 模式,包含了一系列扫描活动流程操作,需要把之前的 session 传递进来,方便后续我们直接通过该类进行操作:

图片 5图片 6

    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();
        }
    }

NessusManager.cs

 

  代码分析:

  安装完毕 Nessus 之后,我们可以选择合适的扫描模板:

图片 7

  通过 GetScanPolicies() 方法,我们就可以查看模板信息,这里的每一种模板都有对应的 UUID(又称 GUID):

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

 

  获取到我们选择的模板 id 后,我们可以通过 CreateScanJob() 方法把 id 和其它所需要的参数进行传入,即可创建扫描任务:

        /// <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);
        }

 

  创建完毕之后,我们可以得到该任务 id(参数 scanId),通过 StartScan() 方法就可以直接启动对应的扫描任务。

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

 

  通过定时调用 GetScanResult() 方法,我们可以以轮询的方式不断跟踪该计划的进度和状态,类似订单跟踪,参数依然是之前创建任务返回所得到的 id(scanId):

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

 

当然,直接运行就有答案了,还是要仔细想一下,反正看到我第一次跑出的结果的时候,我都不敢相信自己的眼睛。

 Swift:

操作测试

  目前已经编写好两个主要参与的类,下面来演示一下如何通过类 NessusManager 来完成一个基本的扫描流程:

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

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

                using (var manager = new NessusManager(session))
                {
                    var policies = manager.GetScanPolicies();
                    var id = string.Empty;

                    foreach (var template in policies.templates)
                    {
                        if (template.name != "basic") continue;

                        id = template.uuid;
                        break;
                    }

                    var job = manager.CreateScanJob(id, "117.48.203.231", "随便扫扫", "该用户很懒,什么也没有留下");
                    int scanId = job.scan.id;

                    manager.StartScan(scanId);

                    var scanResult = manager.GetScanResult(scanId);

                    while (scanResult.info.status != "completed")
                    {
                        Console.WriteLine("扫描状态:" + scanResult.info.status);
                        Thread.Sleep(5000);
                        scanResult = manager.GetScanResult(scanId);
                    }

                    Console.WriteLine(scanResult);

                    foreach (var vulnerability in scanResult.vulnerabilities)
                    {
                        Console.WriteLine(vulnerability);
                    }
                }
            }
        }

 

  在代码中,通过 manager 对象,我用 GetScanPolicies() 方法选取了名称为“basic”(“Basic Network Scan”)的模板进行创建,再调用 CreateScanJob() 方法创建扫描任务,接着调用 StartScan() 方法启动,轮询 GetScanResult() 方法返回的结果值输出,根据不同人的服务器运行速度以及网络环境等因素,整个时间可能比较漫长。

  因为每一种模板都有标识 id,通过 manager.CreateScanJob(id, "117.48.203.231", "随便扫扫", "该用户很懒,什么也没有留下") 方法创建的就是指定模板的扫描任务,后面的三个参数对应的参数值如下图所示,其中 59 是创建完 job 后返回的 scanId,即代码中的 job.scan.id。下图的 Targets 参数表示的是被扫描者的 IP,可以多个,可以是互联网上别人的 IP。

图片 8

 

  最后我们通过 scanResult.vulnerabilities 可以得到风险提示或建议等信息:

图片 9

  对应的 Web 端的截图:

图片 10

 

 

 */

step1:

var intValue:Int = 10

几个概念:

var doubleValue:Double

继承的功能:父类的代码重用

doubleValue = Double(intValue)

多态的功能:同一方法对不同类型的对象会有相应的结果

// 注意:Double()并不会修改intValue的值, 而是通过intValue的值生成一个临时的值赋值给doubleValue

开闭原则:对扩展开放,对修改封闭

print(intValue)

super类功能:新式类实现广度优先的不重复的调用父类,解决了钻石继承(多继承)的难题

print(doubleValue)

 

/*

step2:

 C语言和OC并没有真正的Bool类型

super实现原理:通过c3算法,生成mro(method resolution order)列表,根据列表中元素顺序查询调用

 C语言的Bool类型非0即真

新式类调用顺序为广度优先,旧式类为深度优先

本文由澳门新葡亰手机版发布于编程,转载请注明出处:动态构建扫描任务计划,用法和原理

上一篇:帮助类等 下一篇:WebAPI设置路由和参数2,相关语法进阶
猜你喜欢
热门排行
精彩图文