我正在验证ARM v6 / v7平台上XN位的硬件支持。为此我在ARM上执行了execstack.c。由于ARM v6 / v7支持XN位,因此崩溃了。然后我在MIPS目标(34Kc)上检查了相同的,它没有XI位支持,因此程序必须正常执行,但是这里程序也崩溃了。然后我删除了XN位代码并为ARM编译。然后程序崩溃,不应该。
测试程序/ * execstack.c - 测试堆栈上的代码是否可以执行
*/
typedef void (*fptr)(void);
char *testname = "Executable stack ";
void itworked( void )
{
printf( "Vulnerable\n" );
exit( 1 );
}
void doit( void )
{
char buf[8192];
fptr func;
/* Put a RETN instruction in the buffer */
buf[0] = '\xc3';
/* Convert the pointer to a function pointer */
func = (fptr)buf;
/* Call the code in the buffer */
func();
/* It worked when the function returns */
itworked();
}
int main( int argc, char *argv[] )
{
int status;
printf( "%s: ", testname );
fflush( stdout );
if( fork() == 0 ) {
do_mprotect((unsigned long)argv & ~4095U, 4096, PROT_READ|PROT_WRITE|PROT_EXEC);
doit();
} else {
wait( &status );
if( WIFEXITED(status) == 0 ) {
printf( "Killed\n" );
exit( 0 );
}
}
exit( 0 );
}
void itfailed( void )
{
printf( "Ok\n" );
exit( 2 );
}
int do_mprotect( const void *addr, size_t len, int prot )
{
void *ptr;
int retval;
/* Allign to a multiple of PAGESIZE, assumed to be a power of two */
ptr = (char *)(((unsigned long) addr) & ~(PAGESIZE-1));
retval = mprotect( ptr, len, prot );
if( retval != 0 && errno == EINVAL ) {
perror( "could not mprotect():" );
exit( 1 );
}
return retval;
}
/登录MIPS目标/
在MIPS上,execstack测试用例给出了下面的coredump,尽管我假设MIPS不支持XI位。
VDLinux#> ./execstack
可执行堆栈[53.272000] do_ri():将SIGILL发送到execstack,PID:386
杀害
/登录ARM目标/
VDLinux#> ./execstack
可执行堆栈[451.784000] execstack:0xbead5860处的未处理页错(11),代码0x80000007已杀
所以我有以下问题:
谢谢,Girish
我编写了下面的汇编代码来测试ARM目标上的XN位支持。
.text
.global _start
_start:
mov r0, #1 (output)
add r1, pc, #20 (string)
mov r2, #12 strlen(string))
mov r7, #4 (syscall number for write)
svc 0x0
mov r0, #0 (output)
mov r7, #1 (syscall number for exit)
svc 0x0
.asciz "Hello world\n "
从装配生成机器:
arm-linux-gnueabi-gcc -c -o arm_hello.o arm_hello.s
arm-linux-gnueabi-ld arm_hello.o -o arm_hello
反汇编.text:
root@oss:shellcode_2# arm-linux-gnueabi-objdump -d arm_hello
arm_hello : file format elf32-littlearm
00008054 <_start>:
8054: e3a00001 mov r0, #1
8058: e28f1014 add r1, pc, #20
805c: e3a0200c mov r2, #12
8060: e3a07004 mov r7, #4
8064: ef000000 svc 0x00000000
8068: e3a00000 mov r0, #0
806c: e3a07001 mov r7, #1
8070: ef000000 svc 0x00000000
8074: 6c6c6548 .word 0x6c6c6548
8078: 6f77206f .word 0x6f77206f
807c: 0a646c72 .word 0x0a646c72
8080: 00202020 .word 0x00202020
C中的最终Shell代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <asm/unistd.h>
typedef void (*fptr) (void);
void
main ()
{
unsigned char hellocode[] = "\x01\x00\xa0\xe3\x14\x10\x8f\xe2"
"\x0c\x20\xa0\xe3\x04\x70\xa0\xe3"
"\x00\x00\x00\xef\x00\x00\xa0\xe3"
"\x01\x70\xa0\xe3\x00\x00\x00\xef" "hello world\n \0";
unsigned char buffcode[256] __attribute__ ((aligned (32)));
fptr func;
memcpy (buffcode, hellocode, 49);
/* Convert the pointer to a function pointer */
func = (fptr) buffcode;
/* flush contents of instruction and/or data cache */
syscall (__ARM_NR_cacheflush, buffcode, buffcode + 50, 0);
/* Call the code in the buffer */
(*func) ();
}
案例1:当堆栈可执行时:
程序汇编:
root@oss:shellcode_ final# arm-linux-gnueabi-gcc stack.c -z execstack -o stack_RWX
阅读ELF标题:
root@oss:shellcode_final# arm-v7a9v3r0-linux-gnueabi-readelf -l stack_RWX
Elf file type is EXEC (Executable file)
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
运行程序:此处堆栈是可执行的,因此XN位将被清除(0)。程序将正常运行。
ARM_Target#> ./stack_RWX
hello world
情况2:当堆栈不可执行时:
程序汇编:
root@oss:shellcode_ final# arm-v7a15v3r1-linux-gnueabi-gcc stack.c -o stack_RW
阅读ELF标题:
root@oss:shellcode_final# arm-linux-gnueabi-readelf -l stack_RW
Elf file type is EXEC (Executable file)
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
运行程序:由于此处XN位已设置(它为1),因此我们将在每种情况下获得分段错误。
ARMtarget#> ./stack_RW
[ 39.092000] stack_RW: unhandled page fault (11) at 0xbeca8760, code 0x8000000f
[ 41.000000] [VDLP COREDUMP] SIGNR:11
Segmentation fault (core dumped)
在ARM中禁用XN位的补丁:我创建了一个补丁。在这个补丁中,我们评论了汇编代码的一部分。这是在arch / arm / mm / proc-v7.S中完成的
#ifdef CONFIG_XN_SUPPORT
tst r1, #L_PTE_XN
orrne r3, r3, #PTE_EXT_XN
#endif
如果取消选择CONFIG_XN_SUPPORT选项,PTE_EXT_XN位将始终为0.因此,无论堆栈是否可执行,都将执行所有二进制文件。
运行程序:
ARM_Target#> ./stack_RWX
hello world
ARM_Target#> ./stack_RW
hello world
结论: Cortex-A15 ARMv7支持XN位。