by cawan (cawan[at]ieee.org or chuiyewleong[at]hotmail.com)
on 7/11/2012
In exploiting embedded linux system, it is crucial to ensure ASLR and NX features are
enabled or not. If both of the features are enabled, then we need to apply ROP with
offset comparison technique in creating shellcode to work with the exploit. If any of
them is disabled, then it is much simpler to be compromised. Let's start from how to
check an embedded linux system has ASLR and NX features enabled or not first. For ASLR,
it is really simple by checking the user and kernel modules layout in memory before
and after the system reboot. Let's show with an example.
Before Reboot,
tango3[bin]# cat /proc/modules
em8xxx 935488 0 - Live 0xc01b8000 (PF)
llad 144800 1 em8xxx, Live 0xc00b0000 (P)
sigmablock 70976 3 - Live 0xc002c000 (P)
tango3[bin]# cat /proc/self/maps
00400000-004b0000 r-xp 00000000 00:01 387 /bin/busybox
004bc000-004c0000 rw-p 000ac000 00:01 387 /bin/busybox
004c0000-004c4000 rwxp 004c0000 00:00 0 [heap]
2aaa8000-2aac8000 r-xp 00000000 00:01 624 /lib/ld-2.8.so
2aac8000-2aacc000 rw-p 2aac8000 00:00 0
2aad4000-2aad8000 rw-p 0001c000 00:01 624 /lib/ld-2.8.so
2aad8000-2ab54000 r-xp 00000000 00:01 514 /lib/libm-2.8.so
2ab54000-2ab60000 ---p 0007c000 00:01 514 /lib/libm-2.8.so
2ab60000-2ab64000 rw-p 00078000 00:01 514 /lib/libm-2.8.so
2ab64000-2acac000 r-xp 00000000 00:01 630 /lib/libc-2.8.so
2acac000-2acb8000 ---p 00148000 00:01 630 /lib/libc-2.8.so
2acb8000-2acc0000 r--p 00144000 00:01 630 /lib/libc-2.8.so
2acc0000-2acc4000 rw-p 0014c000 00:01 630 /lib/libc-2.8.so
2acc4000-2acc8000 rw-p 2acc4000 00:00 0
7fb84000-7fbd8000 rwxp 7fb84000 00:00 0 [stack]
After Reboot,
tango3[bin]# cat /proc/modules
em8xxx 935488 0 - Live 0xc01b8000 (PF)
llad 144800 1 em8xxx, Live 0xc00b0000 (P)
sigmablock 70976 3 - Live 0xc002c000 (P)
tango3[bin]# cat /proc/self/maps
00400000-004b0000 r-xp 00000000 00:01 387 /bin/busybox
004bc000-004c0000 rw-p 000ac000 00:01 387 /bin/busybox
004c0000-004c4000 rwxp 004c0000 00:00 0 [heap]
2aaa8000-2aac8000 r-xp 00000000 00:01 624 /lib/ld-2.8.so
2aac8000-2aacc000 rw-p 2aac8000 00:00 0
2aad4000-2aad8000 rw-p 0001c000 00:01 624 /lib/ld-2.8.so
2aad8000-2ab54000 r-xp 00000000 00:01 514 /lib/libm-2.8.so
2ab54000-2ab60000 ---p 0007c000 00:01 514 /lib/libm-2.8.so
2ab60000-2ab64000 rw-p 00078000 00:01 514 /lib/libm-2.8.so
2ab64000-2acac000 r-xp 00000000 00:01 630 /lib/libc-2.8.so
2acac000-2acb8000 ---p 00148000 00:01 630 /lib/libc-2.8.so
2acb8000-2acc0000 r--p 00144000 00:01 630 /lib/libc-2.8.so
2acc0000-2acc4000 rw-p 0014c000 00:01 630 /lib/libc-2.8.so
2acc4000-2acc8000 rw-p 2acc4000 00:00 0
7f7c8000-7f81c000 rwxp 7f7c8000 00:00 0 [stack]
Most of them are consistent before and after the system reboot, except the stack, but
that is not a problem from the perspective of attacking embedded linux system. So, the
system being tested has ASLR disabled. How about NX ? Regarding to this issue, we first
assume the stack should always be NX protected. So, we will put some instructions in
the stack and then redirect the program counter into it. After that, we step over those
instructions and observe the outcomes. If the outcome is positive, it means the NX is
disabled. Otherwise, if exception incurred, then it means the NX is enabled and run
properly. We will run our test on a MIPS platform with GDB. Let's say we want to create
some instructions to change register $t0 to 0xffffffff now. Well, it is
lui $t0,0xffff
ori $t0,$t0,0xffff
Please refer my previous paper "How To Convert Assembly Instruction Into Machine Code
In Any Type Of Processors Platform" to obtain the respective machine code of that 2
instructions.
Host:# echo 'lui $t0,0xffff' > temp.s && ./mips-linux-gnu-gcc -EL -c temp.s &&
./mips-linux-gnu-objdump -d temp.o | grep 0: | sed s/.*0://
3c08ffff lui t0,0xffff
Host:# echo 'ori $t0,$t0,0xffff' > temp.s && ./mips-linux-gnu-gcc -EL -c temp.s &&
./mips-linux-gnu-objdump -d temp.o | grep 0: | sed s/.*0://
3508ffff ori t0,t0,0xffff
Well, let us put the machine codes into the stack. We need to run a dummy program, set
a breakpoint at _main, then continue the execution, and stop at the breakpoint.
tango3[gdb]# ./gdb ./hello
GNU gdb (GDB) 7.0
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "mips-linux-gnu".
For bug reporting instructions, please see:
Reading symbols from /root/cawan/mips-4.3/bin/gdb-7.0/gdb/hello...
(no debugging symbols found)...done.
Setting up the environment for debugging gdb.
Function "internal_error" not defined.
Make breakpoint pending on future shared library load? (y or [n])
[answered N; input not from terminal]
Function "info_command" not defined.
Make breakpoint pending on future shared library load? (y or [n])
[answered N; input not from terminal]
/root/cawan/mips-4.3/bin/gdb-7.0/gdb/.gdbinit:8: Error in sourced command file:
No breakpoint number 0.
(gdb) break main
Breakpoint 1 at 0x400620
(gdb) run
Starting program: /root/cawan/mips-4.3/bin/gdb-7.0/gdb/hello
Breakpoint 1, 0x00400620 in main ()
(gdb)
Good, we are at the point. Let's check the register info.
(gdb) info reg
zero at v0 v1 a0 a1 a2 a3
R0 00000000 fffffff8 7ff5ba68 2aac8a70 00000001 7ff5bb24 7ff5bb2c 00000000
t0 t1 t2 t3 t4 t5 t6 t7
R8 2ac372f4 0ffffffe 00000002 7ff5ba20 ffffffff 7ff5b978 2aab1b84 f0000000
s0 s1 s2 s3 s4 s5 s6 s7
R16 00400658 004004f0 004cece8 004ced40 00412580 004cece8 004ceda0 004cedb0
t8 t9 k0 k1 gp sp s8 ra
R24 00000000 00400610 00000000 00000000 2ac3d950 7ff5ba30 7ff5ba30 2aaee948
status lo hi badvaddr cause pc
00001c13 00005e17 000001a5 2ab065d0 50808024 00400620
fcsr fir restart
00000000 01739300 00000000
(gdb)
Nice, $t0=2ac372f4, $sp=7ff5ba30, $pc=00400620
Let's check the content of stack.
(gdb) x/16x $sp
0x7ff5ba30: 0x7ff5bb24 0x00400658 0x004004f0 0x004cece8
0x7ff5ba40: 0x2ac3d950 0x00412580 0x00000000 0x2aaee948
0x7ff5ba50: 0x00000000 0x00000001 0x7ff5bb24 0x2aaee7fc
0x7ff5ba60: 0x2ac3d950 0x00000000 0x2aaee908 0x7ff5ba50
(gdb)
Let's change it with our instructions.
(00000000) nop
(00000000) nop
(3c08ffff) lui $t0,0xffff
(3508ffff) ori $t0,$t0,0xffff
(00000000) nop
(00000000) nop
(gdb) set *0x7ff5ba30 = 0x00000000
(gdb) set *(0x7ff5ba30+4) = 0x00000000
(gdb) set *(0x7ff5ba30+8) = 0x3c08ffff
(gdb) set *(0x7ff5ba30+12) = 0x3508ffff
(gdb) set *(0x7ff5ba30+16) = 0x00000000
(gdb) set *(0x7ff5ba30+20) = 0x00000000
(gdb) x/16x $sp
0x7ff5ba30: 0x00000000 0x00000000 0x3c08ffff 0x3508ffff
0x7ff5ba40: 0x00000000 0x00000000 0x00000000 0x2aaee948
0x7ff5ba50: 0x00000000 0x00000001 0x7ff5bb24 0x2aaee7fc
0x7ff5ba60: 0x2ac3d950 0x00000000 0x2aaee908 0x7ff5ba50
(gdb) x/16i $pc
0x7ff5ba30: nop
0x7ff5ba34: nop
0x7ff5ba38: lui t0,0xffff
0x7ff5ba3c: ori t0,t0,0xffff
0x7ff5ba40: nop
0x7ff5ba44: nop
0x7ff5ba48: nop
0x7ff5ba4c: slti t6,s5,-5816
0x7ff5ba50: nop
0x7ff5ba54: movf zero,zero,$fcc0
0x7ff5ba58: 0x7ff5bb24
0x7ff5ba5c: slti t6,s5,-6148
0x7ff5ba60: slti v1,s6,-9904
0x7ff5ba64: nop
0x7ff5ba68: slti t6,s5,-5880
0x7ff5ba6c: subu.ph s7,ra,s5
(gdb)
Fine, the content of stack has been changed to our instructions. Now, let us
redirect our program counter to the stack.
(gdb) set $pc = $sp
warning: GDB can't find the start of the function at 0x7ff5ba30.
(gdb) info reg
zero at v0 v1 a0 a1 a2 a3
R0 00000000 fffffff8 7ff5ba68 2aac8a70 00000001 7ff5bb24 7ff5bb2c 00000000
t0 t1 t2 t3 t4 t5 t6 t7
R8 2ac372f4 0ffffffe 00000002 7ff5ba20 ffffffff 7ff5b978 2aab1b84 f0000000
s0 s1 s2 s3 s4 s5 s6 s7
R16 00400658 004004f0 004cece8 004ced40 00412580 004cece8 004ceda0 004cedb0
t8 t9 k0 k1 gp sp s8 ra
R24 00000000 00400610 00000000 00000000 2ac3d950 7ff5ba30 7ff5ba30 2aaee948
status lo hi badvaddr cause pc
00001c13 00005e17 000001a5 2ab065d0 50808024 7ff5ba30
fcsr fir restart
00000000 01739300 00000000
(gdb)
Well, the program counter is already at the stack, and the $t0 register is 2ac372f4 now.
Let us step over those instructions, and we suppose once the program counter arrived at
the 5th instruction, register $t0 should be changed into 0xffffffff. Let's see.
(gdb) ni
warning: GDB can't find the start of the function at 0x7ff5ba34.
0x7ff5ba34 in ?? ()
(gdb) ni
warning: GDB can't find the start of the function at 0x7ff5ba38.
0x7ff5ba38 in ?? ()
(gdb) ni
warning: GDB can't find the start of the function at 0x7ff5ba3c.
0x7ff5ba3c in ?? ()
(gdb) ni
warning: GDB can't find the start of the function at 0x7ff5ba40.
0x7ff5ba40 in ?? ()
(gdb) ni
warning: GDB can't find the start of the function at 0x7ff5ba44.
0x7ff5ba44 in ?? ()
(gdb) info reg
zero at v0 v1 a0 a1 a2 a3
R0 00000000 fffffff8 7ff5ba68 2aac8a70 00000001 7ff5bb24 7ff5bb2c 00000000
t0 t1 t2 t3 t4 t5 t6 t7
R8 ffffffff 0ffffffe 00000002 7ff5ba20 ffffffff 7ff5b978 2aab1b84 f0000000
s0 s1 s2 s3 s4 s5 s6 s7
R16 00400658 004004f0 004cece8 004ced40 00412580 004cece8 004ceda0 004cedb0
t8 t9 k0 k1 gp sp s8 ra
R24 00000000 00400610 00000000 00000000 2ac3d950 7ff5ba30 7ff5ba30 2aaee948
status lo hi badvaddr cause pc
00001c13 00005e17 000001a5 2ab065d0 50808024 7ff5ba44
fcsr fir restart
00000000 01739300 00000000
(gdb)
Awesome, the register $t0 has eventually changed to 0xffffffff. So, the MIPS platform
under test has NX disabled. In other words, it is easy to design shellcode to work with
appropriate exploit in attacking this platform.
pdf version:
http://www.scribd.com/doc/112540003/How-to-Check-for-ASLR-and-NX-Features-of-Embedded-Linux-System-1
No comments:
Post a Comment