当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-092703

漏洞标题:LebiShop商城系统最新版SQL注入一(同一文件多处)

相关厂商:www.lebi.cn

漏洞作者: xfkxfk

提交时间:2015-01-23 11:18

修复时间:2015-04-23 11:20

公开时间:2015-04-23 11:20

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-01-23: 细节已通知厂商并且等待厂商处理中
2015-01-26: 厂商已经确认,细节仅向厂商公开
2015-01-29: 细节向第三方安全合作伙伴开放
2015-03-22: 细节向核心白帽子及相关领域专家公开
2015-04-01: 细节向普通白帽子公开
2015-04-11: 细节向实习白帽子公开
2015-04-23: 细节向公众公开

简要描述:

LebiShop商城系统最新版SQL注入一,同一文件多处,官方demo演示

详细说明:

LebiShop商城系统最新版V3.1.00,多处存在SQL注入漏洞,可拖库
更多案例:
使用关键字搜索:powered by LebiShop
可搜索大量使用用户
反编译/bin/shop.dll,在SHop.Ajax中的Ajax_order文件中存在多处SQL注入漏洞

1.png


SHop.Ajax.Ajax_order即根目录下的Ajax目录,Ajax_order文件
第一处SQL注入
我们来看看Ajax_order文件中的Address_Del方法:

// Shop.Ajax.Ajax_order
public void Address_Del()
{
string id = RequestTool.RequestString("id");
if (id == "")
{
base.Response.Write("{\"msg\":\"" + base.Tag("请选择要删除的信息") + "\"}");
return;
}
B_Lebi_User_Address.Delete(string.Concat(new object[]
{
"User_id = ",
this.CurrentUser.id,
" and id in(",
id,
")"
}));
if (B_Lebi_User_Address.GetModel(string.Concat(new object[]
{
"User_id = ",
this.CurrentUser.id,
" and id = ",
this.CurrentUser.User_Address_id
})) == null)
{
Lebi_User_Address models = B_Lebi_User_Address.GetModel("User_id = " + this.CurrentUser.id);
if (models != null)
{
this.CurrentUser.User_Address_id = B_Lebi_User_Address.GetMaxId("User_id=" + this.CurrentUser.id);
}
B_Lebi_User.Update(this.CurrentUser);
}
base.Response.Write("{\"msg\":\"OK\"}");
}


参数通过RequestTool.RequestString获取,跟进RequestTool.RequestString方法

// Shop.Tools.RequestTool
public static string RequestString(string nKey, string def)
{
string ojb = HttpContext.Current.Request.QueryString[nKey];
if (ojb != null)
{
return StringTool.InjectFiltrate(ojb.Trim());
}
ojb = HttpContext.Current.Request.Form[nKey];
if (ojb != null)
{
return StringTool.InjectFiltrate(ojb.Trim());
}
return def;
}


id参数又通过StringTool.InjectFiltrate过滤处理:

// Shop.Tools.StringTool
public static string InjectFiltrate(string str)
{
if (!StringTool.IsSafeSqlString(str))
{
str = str.Replace("'", "´");
}
return str;
}


这里的过滤只是转义了单引号
再回到我们的Address_Del方法中
id通过处理后,进入了B_Lebi_User_Address.Delete方法中
而且这里的id进入了in条件中,没有使用单引号保护,继续跟进B_Lebi_User_Address.Delete方法

public void Delete(string strWhere)
{
if (strWhere.IndexOf("}") > 0)
{
SQLPara para = new SQLPara(strWhere, "", "");
this.Delete(para);
}
StringBuilder strSql = new StringBuilder();
strSql.Append("delete from [Lebi_User_Address] ");
strSql.Append(" where " + strWhere);
SqlUtils.SqlUtilsInstance.TextExecuteNonQuery(strSql.ToString());
}


可以看到这里的条件strWhere也没有加处理,直接进入了delete sql语句中,导致注入
第二处SQL注入
order_save方法:

// Shop.Ajax.Ajax_order
public void order_save()
{
if (this.CurrentUserLevel.BuyRight != 1)
{
base.Response.Write("{\"msg\":\"" + base.Tag("您所在的分组不允许下单") + "\"}");
return;
}
int pay_id = RequestTool.RequestInt("pay_id", 0);
int onlinepay_id = RequestTool.RequestInt("onlinepay_id", 0);
decimal Money_UserCut = RequestTool.RequestDecimal("Money_UserCut", 0m);
int usermoneytype = RequestTool.RequestInt("usermoneytype", 0);
string Pay_Password = RequestTool.RequestString("Pay_Password");
......
string pay2 = RequestTool.RequestString("pay312");
if (pay2 != "")
{
List<Lebi_Card> cs = B_Lebi_Card.GetList(string.Concat(new object[]
{
"User_id=",
this.CurrentUser.id,
" and id in (",
pay2,
")"
}), "id asc");
int flag = cs.FirstOrDefault<Lebi_Card>().IsCanOtherUse;
if (flag == 0 && cs.Count > 1)
{
base.Response.Write("{\"msg\":\"" + base.Tag("代金券异常") + "\"}");
return;
}
foreach (Lebi_Card c in cs)
{
if (flag != c.IsCanOtherUse)
{
base.Response.Write("{\"msg\":\"" + base.Tag("代金券异常") + "\"}");
return;
}
if (!Basket.CheckCard(basket, c))
{
base.Response.Write("{\"msg\":\"" + base.Tag("代金券异常") + "\"}");
return;
}
}
}


可以看到这里的pay2通过RequestTool.RequestString获取
然后没有加单引号保护,进入了in条件语句
最后进入了Getlist函数,跟进:

public List<Lebi_Card> GetList(string strWhere, string strFieldOrder)
{
if (strWhere.IndexOf("}") > 0)
{
SQLPara para = new SQLPara(strWhere, strFieldOrder, "");
return this.GetList(para);
}
StringBuilder strSql = new StringBuilder();
strSql.Append("select * ");
strSql.Append(" FROM [Lebi_Card] ");
if (strWhere.Trim() != "")
{
strSql.Append(" where " + strWhere);
}
if (strFieldOrder.Trim() != "")
{
strSql.Append(" order by " + strFieldOrder);
}
List<Lebi_Card> list = new List<Lebi_Card>();
using (IDataReader dataReader = SqlUtils.SqlUtilsInstance.TextExecuteReader(strSql.ToString()))
{
while (dataReader.Read())
{
list.Add(this.ReaderBind(dataReader));
}
}
return list;
}


在GetList函数中,strWhere也没有进行处理,至今进入了select sql语句,导致sql注入产生
第三处SQL注入
torder_save方法:

// Shop.Ajax.Ajax_order
public void torder_save()
{
int order_id = RequestTool.RequestInt("order_id", 0);
string opid = RequestTool.RequestString("opid");
if (opid == "")
{
base.Response.Write("{\"msg\":\"" + base.Tag("未选择任何商品") + "\"}");
return;
}
int count = 0;
Lebi_Order order = B_Lebi_Order.GetModel(order_id);
if (order == null)
{
base.Response.Write("{\"msg\":\"" + base.Tag("参数错误") + "\"}");
return;
}
if (order.User_id != this.CurrentUser.id)
{
base.Response.Write("{\"msg\":\"" + base.Tag("参数错误") + "\"}");
return;
}
List<Lebi_Order_Product> ops = B_Lebi_Order_Product.GetList("id in (" + opid + ")", "");


同样opid通过RequestTool.RequestString获取
然后opid进入了GetList函数,并且在in条件中,没有引号包含
进入GetList函数后,直接带入查询语句select中,没有处理,导致sql注入

漏洞证明:

以第一处sql注入为例
官方demo演示

2.png


3.png


使用SQLmap即可跑出数据

修复方案:

RequestTool.RequestInt("id")或者进入sql语句时使用单引号保护

版权声明:转载请注明来源 xfkxfk@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:20

确认时间:2015-01-26 11:45

厂商回复:

漏洞已修复,感谢

最新状态:

暂无