1、SQL injection(GET/search) low 输入单引号直接报错,说明有注入点
直接order by二分法得出主查询字段数为7
直接union注入,测出回显点为2,3,4,5
查数据库信息:
测出数据库名为bwapp,用户为root,版本为5.5.53
查询表名:
查询字段名:
查字段值:
没有难度。
medium 尝试多种方法都不行,看了一眼源码:
发现是用addslashes()进行转义的,尝试了下宽字节绕过,也不行。
看了下原来数据库采用的是urf8编码,本来想改成gbk复现一下,结果改不成。
character_set_system:数据库系统使用的编码格式,这个值一直是utf8,不需要设置,它是为存储系统元数据的编码格式。
所以暂时想不到什么绕过方法。
high 使用了mysql_real_escape_string()函数将特殊字符转义
受影响的字符:
暂时无法注入。
2、SQL Injection(GET/Select) 是一个选择表单的格式,但这也不妨碍注入。直接在url中注入
low 输入单引号报错,说明存在注入点。
判断是数字型
order by测出主查询字段数为7
直接union注入
找到了回显点。
查询数据库名 bwapp
查询表名
可以用limit来限制回显个数,也可以用group_concat()一次性查出效率更高
查询字段名
查询数据
medium 虽然用了addslashes()函数进行了转义,但因为是数字型的不需要单引号闭合,所以没什么用,方法和上面一样。
high 采用了PDO技术,做了参数化和预处理,将sql语句和用户输入分离,有效预防了sql注入。
3、SQL Injection (POST/Search) low 由于是post型注入,所以直接burp抓包:
输入单引号直接报错
order by 测到8报错,所以确定主查询为7个字段
测出回显点位2,3,4,5。剩下的就和上面一样了,暴数据库名、表名、字段名、字段值
medium 用了addslashes()函数进行了转义’ " \ null,所以绕过比较困难。
但并不是说,只要加了这个函数就可以防御所有情况,这篇文章给了三种情况:
1、参数没有加引号的,直接绕过
2、宽字节注入(两种情况1.数据库字符集为gbk,2.代码中用了转换字符编码的函数)
3、addslashes()过滤后进行了url解码,直接url双重编码绕过。
总之比较灵活,还是要具体情况具体对待。
但是对这一关而言,绕过还是比较难的。
high 用了mysql_real_escape_string()函数进行了转义,绕过比较困难。
4、SQL Injection (POST/Select) 这一关与SQL Injection(GET/Select)只是请求方式上的差异。
5、SQL Injection (AJAX/JSON/jQuery)
可以看到通过AjAX异步请求发送到sqli_10-2.php,然后其他的和前面一样。
5、SQL Injection(CAPTCHA) 这一关和前面的区别就是多了一道验证码,正确输入验证码进入后,直接注入,手法和之前一样。
6、SQL Injection (Login Form/Hero) 使用万能密码直接登入(需要提前知道用户名)
在用户名的位置进行注入测试:
用order by测出主查询字段数为4
进行union注入:
如图所示,获得回显点为2和4
获取数据库名和用户名:
获取表名:
获取字段名:
获取字段值:
最后将密码利用md5在线解密网站进行解密。
打完收工。
medium级别使用addslashes()进行转义
high级别使用mysql_real_escape_string()函数将特殊字符转义
7、SQL Injection (Login Form/User) 进行注入测试,发现存在sql注入:
order by测出主查询字段数为9,但是无法进一步union注入。
看一眼源码:
发现只有密码通过后面的验证之后才能回显。
而这一段payload回显password值为3,显然无法通过判断。
所以要想进一步注入,就要知道bee账号对应的密码的散列值,这要在实战中直接就拉闸了,顶多能进账户,想脱库很难。
为了演示,假设我们已经知道bee账号对应的散列值,重新更改payload:
如图所示,这样的回显应该可以通过检测了。
试一下:
果然如此,和猜想一致,不过要注意的是password字段的值要加引号,不然会报错。
然后进一步暴数据库名:
接着暴表名、字段名、字段值。
与上一关不同之处在于,上一关在回显之前并没有验证密码,如图所示:
8、SQL Injection - Stored (Blog) 先随便输一个:333
发现直接将输入的语句回显到了页面上,于是判断后台应该是先将用户输入的内容存入数据库,然后查询回显。
语句大概是这样: insert into blog values(username, now(), ‘$content’)
思路一: 所以可以尝试使用报错注入:
insert into blog values(username, now(), ''or updatexml(1,concat(0x7e,database()),2) or ‘’)
如图所示,成功爆出数据库名。
接着暴表名:
暴字段名:
暴字段值:
如图所示,成功爆出用户名和字段的md5值,但是回显的字符串长度有限制,已经被截断了。
于是可以使用substr()函数来截取后一段:
以此类推,将所有的密码截取完拼接起来。
小结:
注意报错注入一定要用concat()函数,否则无法正常回显。
思路二: 还有一种思路是构造闭合,在注入字段的后面字段中做文章。
条件:注入的那个字段,不是insert语句中的最后一个字段。
例如原句为:
insert into blog (login, content, date) values(username, ‘$content’, now())
理想效果:
insert into blog (login,content, date) values(username, ‘hello baby’, database())#’)
这是我们先验证注入字段的位置:
如图所示报错:Column count doesn’t match value count at row 1
说明注入的字段并不是insert语句中的最后一个,满足条件。
于是加一个字段,继续测试:
这一次没有报错,成功插入!
于是可以在后面的那个字段上做文章:
查询数据库名:
暴表名:
暴字段名:
暴字段值:
打完收工!
9、SQL Injection - Stored (User-Agent)
从页面回显的内容来看,猜测网站会将数据包中的host和user-agent字段存入数据库中,然后回显到页面。
所以注入点可能在user-agent字段,然后后端的语句应该是insert
所以报错注入来一波:
如图所示,成功回显数据库名,然后再依次暴表名、字段名、字段值,姿势与上面类似这里不再赘述。
10、SQL Injection - Stored (XML)
点击any bugs然后抓包:
发现请求包的数据是一个xml格式。
于是尝试更改bee为单引号:
结果报错。
分析页面的功能,发现是重置秘密的,所以可能是update语句
于是报错注入来一波:
如图所示,成功爆出数据库名。后续脱库步骤与上面相仿。
源码分析: //sqli_8-1.php< script type = " text/Javascript" > function ResetSecret ( ) { var xmlHttp; if ( window. XMLHttpRequest) { xmlHttp = new XMLHttpRequest ( ) ; } else { xmlHttp = new ActiveXObject ( "Microsoft.XMLHTTP" ) ; } xmlHttp. open ( "POST" , "sqli_8-2.php" , true ) ; xmlHttp. setRequestHeader ( "Content-type" , "text/xml; charset=UTF-8" ) ; xmlHttp. send ( "login"])){echo $_SESSION[" login"];}?> Any bugs? " ) ; } script>
$body = file_get_contents ( "php://input" ) ; if ( $_COOKIE [ "security_level" ] != "1" && $_COOKIE [ "security_level" ] != "2" ) { ini_set ( "display_errors" , 1 ) ; $xml = simplexml_load_string ( $body ) ; $login = $xml - > login ; $secret = $xml - > secret ; if ( $login && $login != "" && $secret ) { $sql = "UPDATE users SET secret = &#39;" . $secret . "&#39; WHERE login = &#39;" . $login . "&#39;" ; / / echo $sql ; $recordset = $link - > query ( $sql ) ; if ( ! $recordset ) { die ( "Connect Error: " . $link - > error ) ; } $message = $login . "&#39;s secret has been reset!" ; }
从上面的代码可以看出,sqli_8-1.php利用Ajax技术将xml数据发送到sqli_8-2.php后,进行xml解析,然后没有进行任何过滤直接将解析的数据拼接到sql语句中执行了,所以造成sql注入漏洞。修复方法:在拼接sql语句之前,将参数进行过滤或转义,或者使用PDO技术进行预处理和参数化。
相关函数:
file_get_contents(“php://input”) //访问请求的原始数据的只读流 详细
simplexml_load_string() //函数转换形式良好的 XML 字符串为 SimpleXMLElement 对象
11、SQL Injection - Blind - Boolean-Based 输入单引号直接报错:
经过多次尝试,无论输入什么都只会回显The movie exists in our database!和The movie does not exist in our database!两种情况。如下图:
于是判断是布尔盲注。
//猜解数据库名
先猜解数据库名长度
测出数据库名的第一个字母ascii为96(b)
以此类推一共猜解5次测出数据库名为bwapp;
//猜解表名
先猜解数据库中表的数量
二分法测出表的数量为5
猜解第一个表的长度:
二分法猜解出表的长度为4
猜解第一个表的第一个字母
二分法测出为98(b)
然后通过更改substr的参数更换字母,逐个猜解出表名的每个字母;然后再更改limit的参数更换表名,重复上述过程猜解出每张表的表名。最后猜解出表名依次为blog,heroes,movies,users,visitors。
//猜解字段名,字段值与上述过程相仿。
总结猜解三步走:
1、猜解数量
例:and (select count(table_name) from information_schema.tables where table_schema=database())>6
2、猜解长度
例:and length(select table_name from information_schema.tables where table_schema=database() limit 0,1)>5
3、猜解值
例:and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>110
以上三步不断迭代方可制胜
12、SQL Injection - Blind - Time-Based 如图所示,根据回显延迟的大小就可判断。只需将布尔注入的语句与if函数和sleep函数相结合便可完成注入。
扔进sqlmap中一会就完事。
收获 关于addslashes()函数绕过的三种方式
报错注入时一定要与concat()函数相结合,不然无法正常回显
报错注入的两种思路
盲注时三步走:猜解数量、猜解长度、猜解值