flat assembler
Message board for the users of flat assembler.
Index
> Windows > Calling UEFI from ms win |
Author |
|
Feryno 25 Sep 2012, 12:59
I created some samples which call uefi from ms win. It is possible from ring3 applications using GetFirmwareEnvironmentVariable/SetFirmwareEnvironmentVariable
If the system is UEFI based but the OS is booted via BIOS emulation the system calls fail (return 0). By my opinion here is a dangerous security hole - it is possible to write malicious bootloader into e.g. removable media like USB stick (into something like EFI\boot\bootx64.efi), write new Bootxxxx variable, change BootOrder so newly created Bootxxxx is the first in boot order and reboot PC... Anyway turning ON Secure Boot (if it is available) closes this security hole because preventing to load unsigned bootloaders (as it also complicates life for Linux UEFI bootloaders, time will show whether Secure Boot becomes widespread) here the sample which obtains boot order Code: format PE64 GUI at (1 shl 32) on 'nul' include '%fasminc%\win64a.inc' include 'WinNT.h.inc' section '.code' code readable executable entry $ push rbx rbp sub rsp,8*(4+11) lea r8,[rsp+8*(4+10)] mov edx,MAXIMUM_ALLOWED ; desired access ; mov edx,TOKEN_ADJUST_PRIVILEGES ; desired access or rcx,-1 ; hCurrentProcess call [OpenProcessToken] or eax,eax jz exit pxor xmm0,xmm0 movdqa [rsp+8*(4+0)],xmm0 ; 5th and 6th param xor r9,r9 lea r8,[rsp+8*(4+2)] virtual at r8 tp TOKEN_PRIVILEGES end virtual mov [tp.PrivilegeCount],1 mov [tp.Privileges.Luid.usedpart],SE_SYSTEM_ENVIRONMENT_PRIVILEGE and [tp.Privileges.Luid.ignorehigh32bitpart],0 mov [tp.Privileges.Attributes],SE_PRIVILEGE_ENABLED xor edx,edx mov rcx,[rsp+8*(4+10)] call [AdjustTokenPrivileges] mov ebx,eax mov rcx,[rsp+8*(4+10)] call [CloseHandle] or ebx,ebx ; AdjustTokenPrivileges success? jz exit lea rcx,[kernel_name] call [LoadLibraryA] or rax,rax jz exit lea rdx,[_GetFirmwareEnvironmentVariableA] mov rcx,rax call [GetProcAddress] or rax,rax jz exit mov rbp,rax ; DWORD WINAPI GetFirmwareEnvironmentVariable( ; __in LPCTSTR lpName, ; __in LPCTSTR lpGuid, ; __out PVOID pBuffer, ; __in DWORD nSize ; ); ; Parameters ; lpName [in] ; The name of the firmware environment variable. The pointer must not be NULL. ; lpGuid [in] ; The GUID that represents the namespace of the firmware environment variable. The GUID must be a string in the format "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where 'x' represents a hexadecimal value. ; pBuffer [out] ; A pointer to a buffer that receives the value of the specified firmware environment variable. ; nSize [in] ; The size of the pBuffer buffer, in bytes. ; ; Return value ; If the function succeeds, the return value is the number of bytes stored in the pBuffer buffer. ; If the function fails, the return value is zero. To get extended error information, call {GetLastError}. Possible error codes include ERROR_INVALID_FUNCTION. ; On a legacy BIOS-based system, or on a system that supports both legacy BIOS and UEFI where Windows was installed using legacy BIOS, the function will fail with ERROR_INVALID_FUNCTION. ; On a UEFI-based system, the function will fail with an error specific to the firmware, such as ERROR_NOACCESS, to indicate that the dummy GUID namespace does not exist. mov r9d,variable_buffer_max_size lea r8,[variable_buffer] lea rdx,[EFI_GLOBAL_VARIABLE_Vendor_GUID] lea rcx,[EfiVariableName] call rbp or eax,eax jz exit ; eax = size of variable lea r11,[variable_buffer] lea r10,[show_buf] movdqa xmm3,dqword [Sum1] movdqa xmm4,dqword [Comp1] movdqa xmm2,dqword [Mask1] movdqa xmm5,dqword [Num1] mov dl,'.' L0: movq xmm0,[r11] movdqa xmm1,xmm0 psrlq xmm0,4 pand xmm0,xmm2 pand xmm1,xmm2 punpcklbw xmm0,xmm1 movdqa xmm1,xmm0 pcmpgtb xmm0,xmm4 pand xmm0,xmm5 paddb xmm1,xmm3 paddb xmm1,xmm0 movdqu dqword [r10],xmm1 mov byte [r10+16],' ' movq xmm0,[r11+8] movdqa xmm1,xmm0 psrlq xmm0,4 pand xmm0,xmm2 pand xmm1,xmm2 punpcklbw xmm0,xmm1 movdqa xmm1,xmm0 pcmpgtb xmm0,xmm4 pand xmm0,xmm5 paddb xmm1,xmm3 paddb xmm1,xmm0 movdqu dqword [r10+16+1],xmm1 add r10,16+1+16 mov byte [r10],' ' inc r10 repeat 16 mov cl,[r11] inc r11 ; or cl,cl ; cmovs ecx,edx ; better to exclude 7Fh also cmp cl,7Fh cmovnc ecx,edx cmp cl,' ' cmovc ecx,edx mov [r10],cl inc r10 end repeat mov word [r10],0A0Dh add r10,2 sub eax,16 jnbe L0 if MB_OK = 0 xor r9d,r9d else mov r9d,MB_OK end if lea r8,[EfiVariableName] lea rdx,[show_buf] xor ecx,ecx call [MessageBoxA] exit: xor ecx,ecx call [ExitProcess] add rsp,8*(4+11) pop rbp rbx xor eax,eax ret section '.data' data readable writeable align 10h Sum1 dq 3030303030303030h, 3030303030303030h Mask1 dq 0f0f0f0f0f0f0f0fh, 0f0f0f0f0f0f0f0fh Comp1 dq 0909090909090909h, 0909090909090909h Num1 dq 0707070707070707h, 0707070707070707h align 10h EFI_GLOBAL_VARIABLE_Vendor_GUID db '{8BE4DF61-93CA-11D2-AA0D-00E098032B8C}',0 ; N.B. boot into UEFI Shell and use command: ; dumpstore -b ; look into UEFI spec, chapter 3, Table 10. Global Variables align 10h EfiVariableName db 'BootOrder',0 ; db 'Boot0000',0 ; db 'ConOut',0 ; this is maybe my ASUS vendor: ; {4599D26F-1A11-49B8-B91F-858745CFF824}, 'StdDefaults',0 align 10h _GetFirmwareEnvironmentVariableA db 'GetFirmwareEnvironmentVariableA',0 section '.bss' data readable writeable variable_buffer_max_size = 1000h variable_buffer rb variable_buffer_max_size show_buf rb variable_buffer_max_size*7 section '.idata' import data readable writeable dd 0,0,0,RVA kernel_name, RVA kernel_table dd 0,0,0,RVA user_name, RVA user_table dd 0,0,0,RVA advapi_name, RVA advapi_table dd 0,0,0,0,0 kernel_table: CloseHandle dq RVA _CloseHandle ExitProcess dq RVA _ExitProcess GetProcAddress dq RVA _GetProcAddress LoadLibraryA dq RVA _LoadLibraryA dq 0 user_table: MessageBoxA dq RVA _MessageBoxA dq 0 advapi_table: AdjustTokenPrivileges dq RVA _AdjustTokenPrivileges OpenProcessToken dq RVA _OpenProcessToken dq 0 kernel_name db 'KERNEL32.DLL',0 user_name db 'USER32.DLL',0 advapi_name db 'ADVAPI32.DLL',0 ; kernel32.dll: _CloseHandle db 0,0,'CloseHandle',0 _ExitProcess db 0,0,'ExitProcess',0 _GetProcAddress db 0,0,'GetProcAddress',0 _LoadLibraryA db 0,0,'LoadLibraryA',0 ; user32.dll _MessageBoxA db 0,0,'MessageBoxA',0 ; advapi32.dll _AdjustTokenPrivileges db 0,0,'AdjustTokenPrivileges',0 _OpenProcessToken db 0,0,'OpenProcessToken',0 the first word reported by boot order is the first bootxxxx when booting (it is usually Boot0000, but it is possible to change it) then change this: Code: EfiVariableName db 'BootOrder',0 to this: Code: EfiVariableName db 'Boot0000',0 recompile and run the app again you will see where is the ms win bootloader (ms creates hidden FAT32 partition for its bootloader, the path and file should be \efi\Microsoft\Boot\bootmgfw.efi) advanced malware may be written into this hidden partition but it requires more effort than USB stick method with CreateFile\WriteFile\CloseHandle (raw access to disk e.g. using \\.\PhysicalDrive0' and reading/writing FAT32 structures of hidden partition by hand) include file required to compile the above sample: WinNT.h.inc: Code: ; Privilege attributes SE_PRIVILEGE_ENABLED_BY_DEFAULT = 00000001h SE_PRIVILEGE_ENABLED = 00000002h SE_PRIVILEGE_REMOVED = 00000004h SE_PRIVILEGE_USED_FOR_ACCESS = 80000000h ; Privilege Set Control flags PRIVILEGE_SET_ALL_NECESSARY = 1 ;typedef struct _PRIVILEGE_SET { ; ULONG PrivilegeCount; ; ULONG Control; ; LUID_AND_ATTRIBUTES Privilege[ANYSIZE_ARRAY]; ; } PRIVILEGE_SET, * PPRIVILEGE_SET; ; These must be converted to LUIDs before use. SE_MIN_WELL_KNOWN_PRIVILEGE = 2 SE_CREATE_TOKEN_PRIVILEGE = 2 SE_ASSIGNPRIMARYTOKEN_PRIVILEGE = 3 SE_LOCK_MEMORY_PRIVILEGE = 4 SE_INCREASE_QUOTA_PRIVILEGE = 5 SE_MACHINE_ACCOUNT_PRIVILEGE = 6 SE_TCB_PRIVILEGE = 7 SE_SECURITY_PRIVILEGE = 8 SE_TAKE_OWNERSHIP_PRIVILEGE = 9 SE_LOAD_DRIVER_PRIVILEGE = 10 SE_SYSTEM_PROFILE_PRIVILEGE = 11 SE_SYSTEMTIME_PRIVILEGE = 12 SE_PROF_SINGLE_PROCESS_PRIVILEGE = 13 SE_INC_BASE_PRIORITY_PRIVILEGE = 14 SE_CREATE_PAGEFILE_PRIVILEGE = 15 SE_CREATE_PERMANENT_PRIVILEGE = 16 SE_BACKUP_PRIVILEGE = 17 SE_RESTORE_PRIVILEGE = 18 SE_SHUTDOWN_PRIVILEGE = 19 SE_DEBUG_PRIVILEGE = 20 SE_AUDIT_PRIVILEGE = 21 SE_SYSTEM_ENVIRONMENT_PRIVILEGE = 22 SE_CHANGE_NOTIFY_PRIVILEGE = 23 SE_REMOTE_SHUTDOWN_PRIVILEGE = 24 SE_UNDOCK_PRIVILEGE = 25 SE_SYNC_AGENT_PRIVILEGE = 26 SE_ENABLE_DELEGATION_PRIVILEGE = 27 SE_MANAGE_VOLUME_PRIVILEGE = 28 SE_IMPERSONATE_PRIVILEGE = 29 SE_CREATE_GLOBAL_PRIVILEGE = 30 SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE = 31 SE_RELABEL_PRIVILEGE = 32 SE_INC_WORKING_SET_PRIVILEGE = 33 SE_TIME_ZONE_PRIVILEGE = 34 SE_CREATE_SYMBOLIC_LINK_PRIVILEGE = 35 SE_MAX_WELL_KNOWN_PRIVILEGE = SE_CREATE_SYMBOLIC_LINK_PRIVILEGE TOKEN_ASSIGN_PRIMARY = 0001h TOKEN_DUPLICATE = 0002h TOKEN_IMPERSONATE = 0004h TOKEN_QUERY = 0008h TOKEN_QUERY_SOURCE = 0010h TOKEN_ADJUST_PRIVILEGES = 0020h TOKEN_ADJUST_GROUPS = 0040h TOKEN_ADJUST_DEFAULT = 0080h TOKEN_ADJUST_SESSIONID = 0100h TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED or \ TOKEN_ASSIGN_PRIMARY or \ TOKEN_DUPLICATE or \ TOKEN_IMPERSONATE or \ TOKEN_QUERY or \ TOKEN_QUERY_SOURCE or \ TOKEN_ADJUST_PRIVILEGES or \ TOKEN_ADJUST_GROUPS or \ TOKEN_ADJUST_DEFAULT or \ TOKEN_ADJUST_SESSIONID TOKEN_READ = STANDARD_RIGHTS_READ or \ TOKEN_QUERY TOKEN_WRITE = STANDARD_RIGHTS_WRITE or \ TOKEN_ADJUST_PRIVILEGES or \ TOKEN_ADJUST_GROUPS or \ TOKEN_ADJUST_DEFAULT TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE struct LUID usedpart dd ? ignorehigh32bitpart dd ? ends struct LUID_AND_ATTRIBUTES Luid LUID Attributes dd ? ends struct TOKEN_PRIVILEGES PrivilegeCount dd ? Privileges LUID_AND_ATTRIBUTES ends STATUS_VARIABLE_NOT_FOUND = 0C0000100h and here you have some reading about possible vulnerabilities of ms win when booting via UEFI http://www.itsec.it/2012/09/18/uefi-technology-say-hello-to-the-windows-8-bootkit/ |
|||
25 Sep 2012, 12:59 |
|
hopcode 25 Sep 2012, 13:26
nice exemplar.
thanks for the link. _________________ ⠓⠕⠏⠉⠕⠙⠑ |
|||
25 Sep 2012, 13:26 |
|
Alphonso 23 Apr 2013, 02:29
oh I missed this one, either I'm too far behind the times or Feryno is way ahead.
Feryno wrote: I created some samples which call uefi from ms win. It is possible from ring3 Doesn't this need admin priv? Shouldn't AdjustTokenPrivileges be checked with GetLastError in case only partial priv's may be assigned? Interesting concept and a lot of things to still come yet with EFI I would think but I'd have to agree with Rev on the admin part. Of course there are people who would grant any software admin rights if requested so still really down to the user in that respect. Not sure that secure boot really achieves any extra security above that on x86 or that UEFI makes things any better, perhaps worse even. |
|||
23 Apr 2013, 02:29 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.