A shellcode is an opaque byte array which if it is in memory and the control is passed to it, it executes a shell (or anything else).Let's start with a program simulating a post-exploit situation: http://
This program should:
- Allocate executable memory.
- Read/load the content of a file (shellcode).
- Pass the control.
Considering the helloworld assembly...
- .section .data
- message:
- .ascii "YOU WIN!\n"
- len = . - message
- .section .text
- .globl _start
- _start:
- #write mesaje to stdout
- movl $len, %edx # LEN
- movl $message, %ecx # BUFFER
- movl $1, %ebx # FD
- movl $4, %eax # WRITE
- int $0x80 # SYSCALL
- #exit
- movl $0, %ebx # RETVALUE
- movl $1, %eax # EXIT
- int $0x80 # SYSCALL
Clearly, this code have 2 different sections or pieces of memory: .text and .data. The code lives in .text and the message in .data.
To assemble it execute:
$ as -32 01-helloworld.s -o 01-helloworld.o
and then you could inspect it with objdump (or nm, readelf, od):
$ objdump -s 01-helloworld.o
01-helloworld.o: file format elf32-i386
Contents of section .text:
0000 ba0b0000 00b90000 0000bb01 000000b8 ................
0010 04000000 cd80bb00 000000b8 01000000 ................
0020 cd80 ..
Contents of section .data:
0000 486f6c61 204d756e 646f0a Hello World. !
The interesting thing is the presence of relocations, i.e. different sections being referenced one from the other. In this case, there is a reference to message which is in .data section from the .text section. The relocations can be inspected with the -r argument.
$objdump -r 01-helloworld.o
01-helloworld.o: file format elf32-i386
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
00000006 R_386_32 .data
Generally, the loader (man ld) is in charge of loading the sections in memory, setting the permissions and resolving the relocations.
ld combines a number of object and archive files, relocates their data and ties up symbol references. Usually the last step in compiling a program is to run ld.
To build a shellcode using the classic toolchain we need code without relocations. The easy way is to generate code that uses only one section (or implement the loader by hand). Ok, to accomplish this we need to do two things:
- Mix the sections in only one section => .text.
- Data will appear following the code (you can invent other layauts)
- Variable references must be calculated taking into account static offsets and the current code position in memory (you can get it from the stack making a call).
- # BASIC SHELLCODE
- .section .text #everything in one section
- .globl _start
- _start:
- call dummy
- dummy: #<--------------------------------\
- popl %ecx #address of dummy in ecx
- #write mesaje to stdout using int 80
- movl $len, %edx # LEN
- # add the distance from dummy to message to get
- # the absolute pointer to message
- # no matter where this code is put in memory
- addl $offset_dummy_to_message, %ecx # buffer
- movl $1, %ebx # FD
- movl $4, %eax # WRITE
- int $0x80 # SYSCALL
- #exit
- movl $0, %ebx # RETVALUE
- movl $1, %eax # EXIT
- int $0x80 # SYSCALL
- # The GNU Assembler knows the sizes of intructions
- # and is able to calculate distances between labels
- # statically at 'assembling' time
- offset_dummy_to_message = message-dummy # This wont generate
- # nothing in the binary
- message:
- # This is in the .text section and inmediatelly
- # after the last instruction
- .ascii "YOU WIN\n"
- len = . - message
As usual it is assembled with this command:
$as -32 02-helloworld-shellcode.s -o 02-helloworld-shellcode.o
$objdump -S 02-holamundo-shellcode.o
$objdump -r 02-holamundo-shellcode.o
To obtain the shellcode from the .text section (you can also get it with objdump -D), we use this python program:
- from elftools.elf.elffile impo
rt ELFFile - import sys
- if len(sys.argv) != 3:
- print "Usage:\t%s file.o file.bin"%sys.argv[0]
- sys.exit()
- #read the ELF object file
- elf = ELFFile(file(sys.argv[1]
)) - #read .text data (abort if not found)
- text = elf.get_section_by_name
('.text').data() - print "Section .text is %d bytes long"%len(text)
- print "Dumping .text section to %s ..."%sys.argv[2]
- file(sys.argv[2],"wb").write(t
ext) - print "done."
Dependencies: https:// bitbucket.org/eliben/ pyelftools/
No comments:
Post a Comment