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

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

缺陷编号:wooyun-2015-093174

漏洞标题:LebiShop商城系统最新版漏洞大礼包

相关厂商:www.lebi.cn

漏洞作者: xfkxfk

提交时间:2015-01-27 15:01

修复时间:2015-04-27 15:02

公开时间:2015-04-27 15:02

漏洞类型:设计缺陷/逻辑错误

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

简要描述:

LebiShop商城系统最新版漏洞大礼包,包括任意用户密码修改,密码重置,某接口直接拖库等

详细说明:

LebiShop商城系统最新版漏洞大礼包
第一个任意用户密码修改
在修改用户登陆密码和支付密码是都没有验证原始密码
在发送修改密码请求时,只需要遍历COOKIE中的userid即可修改全部用户密码
shop.ajax.ajax_userin文件中的setpassword方法

// Shop.Ajax.Ajax_userin
public void SetPassword()
{
string PWD = RequestTool.RequestString("Password");
PWD = EX_User.MD5(PWD);
this.CurrentUser.Password = PWD;
B_Lebi_User.Update(this.CurrentUser);
base.Response.Write("{\"msg\":\"OK\"}");
}


这里直接接受new password,然后跟进当前登陆用户COOKIE中的userid进行修改

8.png


第二密码重置
在找回密码处存在缺陷导致可被重置任意用户密码
shop.ajax.ajax_user文件中的User_forgetpwd方法

// Shop.Ajax.Ajax_user
public void User_forgetpwd()
{
string Email_ = RequestTool.RequestString("Email");
string code = CookieTool.GetCookieString("CheckCodef");
string verifycode = RequestTool.RequestString("verifycode");
if (code != verifycode)
{
base.Response.Write("{\"msg\":\"" + base.Tag("验证码错误") + "\"}");
return;
}
Lebi_User user = B_Lebi_User.GetModel("Email='" + Email_ + "'");
if (user == null)
{
base.Response.Write("{\"msg\":\"" + base.Tag("用户不存在") + "\"}");
return;
}
try
{
Email.SendEmail_forgetpwd(user, base.CurrentTheme);
if (ShopCache.GetBaseConfig().SMS_sendmode.Contains("SMSTPL_getpwd"))
{
SMS.SendSMS_forgetpwd(user);
}
}
catch (Exception ex)
{
base.Response.Write("{\"msg\":\"" + ex.Message + "\"}");
}
base.Response.Write("{\"msg\":\"OK\"}");
}


跟进Email.SendEmail_forgetpwd方法

// Shop.Bussiness.Email
public static void SendEmail_forgetpwd(Lebi_User user, Lebi_Theme CurrentTheme)
{
Lebi_Language lang = B_Lebi_Language.GetModel("Code='" + user.Language + "'");
BaseConfig conf = ShopCache.GetBaseConfig();
user.CheckCode = EX_User.MD5(DateTime.Now.ToString());
B_Lebi_User.Update(user);
string url = string.Concat(new object[]
{
"http://",
RequestTool.GetRequestDomain(),
ThemeUrl.GetURL("P_FindPassword", "", "", lang),
"?id=",
user.id,
"&email=",
user.Email,
"&v=",
user.CheckCode
});
string title = Language.Content(conf.EmailTPL_getpwd_title, user.Language);
string content = Language.Content(conf.EmailTPL_getpwd, user.Language);
title = Email.ReplaceEmailTag(title, user, conf);
content = Email.ReplaceEmailTag(content, user, conf);
content = content.Replace("{$UserPWDURL}", url);
bool flag = Email.Send(user.Email, title, content);
Email.EmailJob(user.Email, title, content, flag, user, conf);
}


这里通过email发送邮件,关键是这里的验证code
user.CheckCode = EX_User.MD5(DateTime.Now.ToString());
CheckCode 只是通过当前时间戳进行md5然后发送重置密码邮件如下:

http://plus.demo.lebi.cn/FindPassword.aspx?id=37&email=2754371317@qq.com&v=207ade4af42016cafd61543e308afae0


最后通过对比userid的用不的CheckCode 是否等于接收到的这个url中的CheckCode
简单的时间戳很容易被绕过,而且这里没有验证发送一次后就情况前面发送的CheckCode ,所以我们可以短时间内发送过个重置密码邮件,比如:
我们在2秒钟内发送多个重置密码请求,然后我们在遍历处2秒钟内的时间戳并md5
然后遍历md5后的字符串构造重置密码请求即可
第三某接口可之直接拖库
来看看代码
shop.api.api文件中的GetUsers方法

// Shop.api.api
public void GetUsers()
{
int id = RequestTool.RequestInt("user_id", 0);
int size = RequestTool.RequestInt("size", 1);
size = ((size < 0) ? 0 : size);
size = ((size > 50) ? 50 : size);
List<Lebi_User> users = B_Lebi_User.GetList("id>=" + id, "id asc", size, 1);
List<apiUser> models = new List<apiUser>();
foreach (Lebi_User user in users)
{
models.Add(new apiUser
{
Address = user.Address,
Password = user.Password,
Area = EX_Area.GetAreaName(user.Area_id, 4),
Birthday = user.Birthday,
CashAccount_Bank = user.CashAccount_Bank,
CashAccount_Code = user.CashAccount_Code,
CashAccount_Name = user.CashAccount_Name,
City = user.City,
Count_Login = user.Count_Login,
Currency_Code = user.Currency_Code,
Email = user.Email,
Face = user.Face,
Fax = user.Fax,
id = user.id,
Introduce = user.Introduce,
IP_Last = user.IP_Last,
IP_This = user.IP_This,
Language = user.Language,
MobilePhone = user.MobilePhone,
Money = user.Money,
Money_xiaofei = user.Money_xiaofei,
Msn = user.Msn,
NickName = user.NickName,
Phone = user.Phone,
Point = user.Point,
Postalcode = user.Postalcode,
QQ = user.QQ,
RealName = user.RealName,
Sex = user.Sex,
Time_Last = user.Time_Last,
Time_lastorder = user.Time_lastorder,
Time_Reg = user.Time_Reg,
Time_This = user.Time_This,
UserName = user.UserName
});
}
JavaScriptSerializer jss = new JavaScriptSerializer();
string json = jss.Serialize(models);
json = jss.Serialize(new LBAPI
{
data = json,
msg = "OK"
});
base.Response.Write(json);
}


这里通过user_id的个数和size参数的大小,遍历出了用户,包括具体信息如代码中的属性信息
但是这里有一个接口密码apipwd

// Shop.api.api
protected void Page_Load(object sender, EventArgs e)
{
string apipwd = RequestTool.RequestString("apipwd");
if (apipwd != ShopCache.GetBaseConfig().APIPassWord)
{
base.Response.Write("{\"msg\":\"验证失败\"}");
return;
}
string action = RequestTool.RequestString("action");
Type type = base.GetType();
MethodInfo methodInfo = type.GetMethod(action);
if (methodInfo != null)
{
methodInfo.Invoke(this, null);
}
}


当请求中的apipwd等于系统中设置的api密码时,即可通过此接口获取全部用户信息
在系统中apipwd是这样获取的:

ShopCache.GetBaseConfig().APIPassWord
model.APIPassWord = ((ht["APIPassWord"] == null) ? "" : ((string)ht["APIPassWord"]));


当默认系统中没有设置APIPassWord时则为空
重要的是此系统默认安装就没有设置APIPassWord,即APIPassWord为空
后台配置,基本设置中

6.png


此时我们提交的请求中可设置apipwd=空即可
如下请求即可获取用户信息

5.png


同理还能获取系统全部订单信息,shop.api.api文件中的GetOrders方法

7.png

漏洞证明:

5.png

修复方案:

验证原始密码,加强验证避免被破解,初始化APIPassWord

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


漏洞回应

厂商回应:

危害等级:中

漏洞Rank:10

确认时间:2015-01-27 17:41

厂商回复:

漏洞已修复,感谢

最新状态:

暂无


漏洞评价:

评论

  1. 2015-01-27 16:09 | sco4x0 ( 实习白帽子 | Rank:31 漏洞数:13 | O_o)

    这厂商已经被X总吓哭了。。。

  2. 2015-04-30 14:41 | BeenQuiver ( 普通白帽子 | Rank:101 漏洞数:26 | 专注而高效,坚持好的习惯千万不要放弃)

    我的天,api开的这么大