m0re

把我的骨灰随身携带 紧急的时候 扬了吧 如果顺风就让我再抱抱你 如果逆风就让我再保护你一次吧!

验证码重放

这个比较没用的属于,但是学习阶段,逻辑很重要。CMS开始审计,相信看的应该都是后台登录的地方。

/admin/cms_login.php

<?php
require_once('../system/inc.php');
if(isset($_POST['submit'])){
    if ($_SESSION['verifycode'] != $_POST['verifycode']) {
        alert_href('验证码错误','cms_login.php');
    }
    null_back($_POST['a_name'],'请输入用户名');
    null_back($_POST['a_password'],'请输入密码');
    null_back($_POST['verifycode'],'请输入验证码');
    $a_name = $_POST['a_name'];
    $a_password = $_POST['a_password'];
    $sql = 'select * from xtcms_manager where m_name = "'.$a_name.'" and m_password = "'.md5($a_password).'"';
    $result = mysql_query($sql);
    if(!! $row = mysql_fetch_array($result)){
        setcookie('admin_name',$row['m_name']);
        setcookie('admin_password',$row['m_password']);
        header('location:cms_welcome.php');
    }else{
        alert_href('用户名或密码错误','cms_login.php');
    }
}
?>

因为看到是数据库查询直接拼接的语句,这里原本以为可以试试注入或者万能密码,再细看,看到后面还有cookie验证,而且不是查询过后直接与传参的数据做对比的,逻辑行不通。

所以还是看看验证码吧。

可以看出验证码是从session中获取的

if ($_SESSION['verifycode'] != $_POST['verifycode']) {
        alert_href('验证码错误','cms_login.php');
    }

如果与验证码匹配,则进行用户名和密码的验证,如果验证码不对,直接跳转回登陆界面。

跟随验证码到system/verifycode.php

<?php
session_start();
$image = imagecreate(50, 34);
$bcolor = imagecolorallocate($image, 0, 0, 0);
$fcolor = imagecolorallocate($image, 255, 255, 255);
$str = '0123456789';
$rand_str = '';
for ($i = 0; $i < 4; $i++){
	$k = mt_rand(1, strlen($str));
	$rand_str .= $str[$k - 1];
}
$_SESSION['verifycode'] = $rand_str; //将生成的验证码保存在SESSION中....
imagefill($image, 0, 0, $bcolor);
imagestring($image, 7, 7, 10, $rand_str, $fcolor);
header('content-type:image/png');
imagepng($image);
?>

无论是在登录处,还是在这个生成验证码的文件中,都没有设置session过期的时间。

在登录的html代码中还有这里

<img src="../system/verifycode.php" onclick="javascript:this.src='../system/verifycode.php?'+Math.random()" style="cursor:pointer;" alt="点击更换" title="点击更换" />

与它绑定的是一个JS点击事件,所以说只要不点击(重新加载JS),就不会刷新验证码。就可以进行用户名和密码暴力破解。

在burp suite中不会重新加载JS,所以可以使用intruder模块进行暴力破解。

其中setcookie()

image-20220114110310126

有关于验证码的漏洞:

  • 查看cookie的是否设置了过期时间
  • 查看验证码验证的次数有没有限制
  • 登陆限制(现在很多登录处设置三次登录机会)

XSS

反射XSS

<?php
$flid1 = $_GET['m'];
if ($flid1 == "") {
$flid1 = '/dongman/list.php?rank=rankhot&page=1';
}
include 'system/360.php';
....
....
<?php echo getPageHtml($page, $fenye, 'dongman.php?m=' . $yourneed . '&page='); ?><li><a><?php echo $fenye; ?></a></li>

传入:"><script>alert(/xss/)</script>没有经过什么过滤就直接回显在前端了。正好闭合前面的href=",然后后面的部分成功执行反弹xss经典弹窗。

img

弹窗效果

img

存储型XSS

先看一些知识

/[\x7f-\xff]+(?:\s*[\x7f-\xff]+)*/
# 这是一个正则表达式,它主要是匹配过滤掉中文字符,看下图

img

//判断有一个空格以上但是又不能全部是空的字符串
	if (!ctype_space($_POST['content']) && !empty($_POST['content'])) {
		//匹配数字字母下划线空格中文 数量不能超过10个字
		if (!preg_match("/[\x7f-\xff]+(?:\s*[\x7f-\xff]+)*/", $_POST['content'])) {
			echo "<script>alert('内容填写不合法!');location.href='book.php'</script>";
			die;
		}
	} else {
		echo "<script>alert('内容填写不合法!');location.href='book.php'</script>";
		die;
	}

其中!ctype_space()

PHP中的ctype_space()函数检查空格字符。如果文本中的每个字符都产生某种空白,则返回TRUE,否则返回FALSE。除空白字符外,还包括制表符,垂直制表符,换行符,回车符和换页符。

意思即为输入的字符串在检查过后,可以存在空格,但是又不能全部是空格,同时又限制了必须输入不为空的内容。

img

所以逻辑是:昵称和留言内容必须是中文字符。但是使用的正则中。

img

只要存在中文字符就行,没有设置为全为中文字符。而且也没有了其他方式的过滤。

而且这个$sql = 'insert into xtcms_book ('.$str[0].') values ('.$str[1].')';还是将数据写入了数据库中,所以即为存储型XSS

防护处理

变量进行htmlspecialchars处理

htmlspecialchars() 函数把预定义的字符转换为 HTML 实体。

预定义的字符是:

& (和号)成为 &
" (双引号)成为 "
' (单引号)成为 '
< (小于)成为 <
> (大于)成为 >
$message = htmlspecialchars( $message );
$name = htmlspecialchars( $name );

标签事件白名单处理

SQL注入

vlist.php(前台注入)

<?php
if (isset($_GET['cid'])) {
		if ($_GET['cid'] != 0){
				$sql = 'select * from xtcms_vod where d_parent in ('.$_GET['cid'].') order by d_id desc';
				$pager = page_handle('page',24,mysql_num_rows(mysql_query($sql)));
				$result = mysql_query($sql.' limit '.$pager[0].','.$pager[1].'');
}else(....)
      ....
}

可以看到SQL语句是拼接的,直接将$_GET['cid']直接拼接到SQL语句中了。

img

没有过滤,直接拼接的SQL语句,存在注入的可能性是非常大的。

/admin/cms_usergroup_edit.php(后台注入)

img

同样是直接拼接SQL语句,所以可以发现在代码审计时,注入漏洞,要针对这种SQL语句多关注一些。同样的地方还有许多。过滤也有很多,绕过暂时不写,CTF中有很多。

一般加控制语句都是在$_GET[‘cid’]后面就加一些自写的过滤函数或者正则匹配,白名单或者黑名单进行过滤。

防护

<?php
/*强制类型转换*/
$id=intval($_GET['id']); //因查询ID为整数 所以可以强制转换为整数
/*转义特殊字符 加上引号 (字符串类型)*/
$id=$pdo->quote($_GET['name']);
/*预处理语句*/
$stmt =$pdo->prepare("SELECT id, name FROM users WHERE id=?;");
$stmt->execute([$_GET['id']]);//简单的预处理 完整使用方法见PHP手册
?>
  1. 强制转换输入内容的类型

  2. 将特殊字符进行转义

  3. 预处理,使用PDO::prepare 预处理SQL语句,有效防止SQL注入

  4. PDO::quote 转义特殊字符并加上引号