本文报道了一个关于 Admin 类型可注入 autoKey 绕过认证的问题。文章描述了在 AdminController.java 中的 changePassOver() 方法和 addOver() 方法中,如何通过判断 admin.getId() 来决定是否对 admin 进行修改密码和添加用户的操作。同时,文章还提到了在 getByAutoKey() 方法中如何获取 admin 实例,并进行相应的操作。
文章速读
Admin类型注入autoKey绕过认证、绕过密码和Google认证获取管理员权限
这一章节描述了一个名为nginxWebUI的软件中的一个漏洞,该漏洞可以通过注入autoKey绕过认证。攻击者可以利用这个漏洞在系统中执行恶意操作,并且不需要输入正确的用户名和密码。为了防止这种漏洞被利用,开发人员需要加强对系统的安全性检查和防范措施。同时,用户也应该注意保护自己的账号信息,避免被黑客攻击。攻击者可以通过向数据库注入autoKey来绕过密码和Google认证,并使用autoLogin接口获得管理员认证。该漏洞存在于两个路由中,即changePassOver和addOver。攻击者只需要在发送数据包时包含autoKey,就能成功注入到数据库。漏洞的发现是通过测试来实现的,最终的结果是在成功注入到数据库后,可以使用autoLogin接口获取管理员认证。
审计过程:
com/cym/controller/adminPage/AdminController.java#changePassOver()
public JsonResult changePassOver(Admin admin) {
adminService.changePassOver(admin);
return renderSuccess();
}
public void changePassOver(Admin admin) {
if (admin.getAuth()) {
Admin adminOrg = sqlHelper.findById(admin.getId(), Admin.class);
if (StrUtil.isEmpty(adminOrg.getKey())) {
admin.setKey(authUtils.makeKey());
}
} else {
admin.setKey("");
}
if (StrUtil.isNotEmpty(admin.getPass())) {
admin.setPass(EncodePassUtils.encode(admin.getPass()));
} else {
admin.setPass(null);
}
sqlHelper.updateById(admin);
}
这里也是对admin.getId()判断,然后来改密码。
com/cym/controller/adminPage/AdminController.java
public JsonResult addOver(Admin admin, String[] parentId) {
if (StrUtil.isEmpty(admin.getId())) {
Long count = adminService.getCountByName(admin.getName());
if (count > 0) {
return renderError(m.get("adminStr.nameRepetition"));
}
} else {
Long count = adminService.getCountByNameWithOutId(admin.getName(), admin.getId());
if (count > 0) {
return renderError(m.get("adminStr.nameRepetition"));
}
}
adminService.addOver(admin, parentId);
return renderSuccess();
}
添加用户的路由, 可以控制admin,parentId,admin.getId()是否为空,不为空进入adminService.getCountByName,跟进getCountByName()
com/cym/service/AdminService.java#getCountByName
public Long getCountByName(String name) {
return sqlHelper.findCountByQuery(new ConditionAndWrapper().eq(Admin::getName, name), Admin.class);
}
可以看到进行sql查询,查看数据库是否存在用户。不存在此用户就在service层面创建用户,跟进adminService.addOver。
com/cym/service/AdminService.java#addOver()
public void addOver(Admin admin, String[] groupIds) {
sqlHelper.insertOrUpdate(admin);
sqlHelper.deleteByQuery(new ConditionAndWrapper().eq(AdminGroup::getAdminId, admin.getId()), AdminGroup.class);
if (admin.getType() == 1 && groupIds != null) {
for (String id : groupIds) {
AdminGroup adminGroup = new AdminGroup();
adminGroup.setAdminId(admin.getId());
adminGroup.setGroupId(id);
sqlHelper.insert(adminGroup);
}
}
}
这个方法直接将admin添加到数据库,deleteByQuery就是根据admin_id删除admin_group的数据,不重要,dmin.getType() == 1就是非管理员,管理员的type为0,不会走到这里。
以上两个路由都接收的Admin admin,
com/cym/model/Admin.java
public class Admin extends BaseModel {
String name;
String pass;
// 谷歌秘钥
String key;
// 是否开启谷歌验证
"false") (
Boolean auth;
// 是否开启api
"false") (
Boolean api;
String token;
// 自动登录key
String autoKey;
// 类型 0 超管 1 受限用户
"0") (
Integer type;
admin类型里面包含了自动登录key,autoKey。
com/cym/controller/adminPage/LoginController.java
public JsonResult autoLogin(String autoKey) {
// 用户名密码
Admin admin = adminService.getByAutoKey(autoKey);
if (admin != null) {
// 登录成功
Context.current().sessionSet("localType", "local");
Context.current().sessionSet("isLogin", true);
Context.current().sessionSet("admin", admin);
Context.current().sessionRemove("imgCode"); // 立刻销毁验证码
// 检查更新
versionConfig.checkVersion();
return renderSuccess(admin);
} else {
return renderError();
}
}
这个功能点可以直接登录,什么二次验证都不用管。
com/cym/service/AdminService.java#getByAutoKey
public Admin getByAutoKey(String autoKey) {
return sqlHelper.findOneByQuery(new ConditionAndWrapper().eq(Admin::getAutoKey, autoKey), Admin.class);
}
就是从数据库取autokey。
所以以上changePassOver,addOver两个路由,在发送数据包的时候只要autoKey,直接就可以注入到数据库,然后通过autoLogin接口传入autoKey即可通过认证,绕过密码、google认证。
漏洞复现
成功注入到数据库
成功注入到数据库
然后调用autoLogin接口,即可获取admin认证。后面就可以利用nginxwebui的命令执行等功能为所欲为了。
已经提交issues,issues如下:https://github.com/cym1102/nginxWebUI/issues/116
原文始发于微信公众号(黑伞安全):1day:NginxWebUI admin认证绕过(全版本通杀)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论