Showing posts with label MicroMike. Show all posts
Showing posts with label MicroMike. Show all posts

Jul 4, 2011

Shell code 5(execve system call)

This article is mainly reference by this website:
smash the stack for fun and profit
This time I'll use execve system call to remove a file called "test".
Before started, let's see how execve works in c.
the man page of execve
#include <unistd.h>
       int execve(const char *filename, char *const argv[],
                  char *const envp[]);

As you can see, there are three formal parameters in execve system call.
1. the filename is the file you want to execute.
2. argv  is  an  array  of argument strings passed to the new program.
3. the last one is not important in our shellcode, so I will not explain it in detail.
Let's write a simple C program which use the execve system call.
execve_pre.c
#include <unistd.h>
int main(){
        char *argv[]={"/bin/rm","./test",NULL};
        execve(argv[0],argv,NULL);
        return 0;
}
compile the program and execute with the following command.
1.gcc -o exe.out execve_pre.c
2.touch test 
P.S the touch command is to create a empty file.
3. ./exe.out

And you will see the "test" is being removed.

Now turn this into the inline assembly.
execve.c
char *argv[]={"/bin/rm","./test",NULL};
int main(){
        __asm__("movl $0xb,%eax;\
                 movl argv,%ebx;\
                 movl $argv,%ecx;\
                 movl $0,%edx;\
                 int $0x80;\
                 movl $0x1,%eax;\
                 movl $0x0,%ebx;\
                 int $0x80;\
                 ");
        return 0;
}
Compile and execute it.
The result is the same as the previous example.
However, as I mentioned before, I don't want the data outside the shellcode.
Therefore, I need to write the data into the shell code. 
And the way I get the address of the data is still the same, the relative jmp/call trick.
The following is the code looks like:
execve2.c

int main(){
        __asm__("jmp 2f;\n\
                 1:;\n\
                 xor %eax,%eax;\n\
                 popl %esi;\n\               
                 movl %esi,%ebx;\n\
                 leal 0x8(%esi),%esi;\n\
                 pushl %eax;\n\
                 pushl %esi;\n\
                 pushl %ebx;\n\               
                 movl $0xb,%eax;\n\
                 movl %esp,%ecx;\n\
                 xorl %edx,%edx;\n\
                 int $0x80;\n\
                 movl $0x1,%eax;\n\
                 movl $0x0,%ebx;\n\
                 int $0x80;\n\
                 2:;\n\
                 call 1b;\n\
                 .string \"/bin/rm\";\n\
                 .string \"./test\";\n\
                 .byte 0x0,0x0,0x0,0x0;\n\
                 ");
        return 0;
}
In order to create a structure like
char *argv[]={"/bin/rm","./test",NULL};
I use the stack to store those data.
1. we get the address of "/bin/rm" by the relative jmp/call trick and pop to the %esi.
2. copy the content of the %esi to %ebx.
3. leal 0x8(%esi), %esi => %esi += 8;
   After the instruction, %esi now point to the "./test"
4. push 0, address of the "./test" and address of the "/bin/rm".
P.S since the stack grows down, push the parameter in reverse order. The memory layout is list in figure 1.
<figure 1>
low ------------------------------------------ high
|address of "/bin/rm"| address of "./test" | NULL
| %ebx               | %esi                | %eax

After doing the above steps, then I can move the parameter to the register which the int $80 need.
1. since the %ebx alrealy contains the address of the structure, there is no need to set it again.
2. movl %esp,%ecx; 
store the address of the structure to the %ecx. This instruction is equal to execve(argv[0],argv,NULL);
3. xorl %edx, %edx
store the NULL pointer to the %edx. This instruction is equal to execve(argv[0],argv,NULL);
And now it's time to compile the source code and execute it.
Use objdump to copy the machine code to the new source file. (If you have no idea how to use it see the previous post of the shell code)
execve3.c
/* This is the shellcode */
char shellcode[] =
"\xeb\x22"
"\x31\xc0"
"\x5e"
"\x89\xf3"
"\x8d\x76\x08"
"\x50"
"\x56"
"\x53"
"\xb8\x0b\x00\x00\x00"
"\x89\xe1"
"\x31\xd2"
"\xcd\x80"
"\xb8\x01\x00\x00\x00"
"\xbb\x00\x00\x00\x00"
"\xcd\x80"
"\xe8\xd9\xff\xff\xff"
"/bin/rm\x0"
"./test\x0"
"\x00\x00\x00\x00";

void main() {
   int *ret;
   /* overflow the return address */
   ret = (int *)&ret + 2;
   (*ret) = (int)shellcode;
}
Compile the source code, use execstack to enable the executable stack and execute it, you will see the result is what we expected.

Actually the execve system call is very dangerous. The above is just using the /bin/rm to remove a file, what if someone use /bin/sh to create a new shell, the consequence is unpredictable.
After verified the result, let's now combine the whole code together.

All.c
/* 
 * The inline assembly mix all the code together.
 * It will print a message,
 * wait 2 seconds and
 * remove a file called test.
 */
int main(){
        __asm__("jmp 2f;\n\
                 1:;\n\
                 popl %esi;\n\
                 movl %esi, %ecx;\n\
                 xorl %ebx, %ebx;\n\
                 mul %ebx;\n\
                 inc %ebx;\n\
                 movb $0x4, %al;\n\
                 movb $0x8, %dl;\n\
                 int  $0x80;\n\
                 xorl %eax, %eax;\n\
                 pushl %eax;\n\
                 movb $0x2, %al;\n\
                 pushl %eax;\n\
                 movl %esp, %ebx;\n\
                 xor %ecx, %ecx;\n\
                 movb $0xa2, %al;\n\
                 int  $0x80;\n\
                 xorl %eax, %eax;\n\
                 leal 0x9(%esi),%esi;\n\
                 pushl %eax;\n\
                 movl %esi, %ebx;\n\
                 leal 0x8(%esi), %esi;\n\
                 pushl %esi;\n\
                 pushl %ebx;\n\
                 movb $0xb, %al;\n\
                 movl %esp, %ecx;\n\
                 xor %edx, %edx;\n\
                 int $0x80;\n\
                 xorl %ebx, %ebx;\n\
                 leal 0x1(%ebx), %eax;\n\
                 int $0x80;\n\
                 2:;\n\
                 call 1b;\n\
                 .string \"Run Han!\"\n\
                 .string \"/bin/rm\";\n\
                 .string \"./test\";\n\
                 .long 0x0;\n\
                ");
        return 0;
}

There is nothing much to tell of the source code. I use some instruction to reduce the code size, I will talk about reduce the code size in the next article.
And now compile the source code and use objdump to generate the shellcode.
All_shell.c
char shellcode[] =
"\xeb\x39"      /*relative jmp*/
"\x5e"          /*pop %esi*/
"\x89\xf1"      /*movl %esi, %ecx*/
"\x31\xdb"      /*xor %ebx, %ebx*/
"\xf7\xe3"      /*mul %ebx*/
"\x43"          /*inc %ebx*/
"\xb0\x04"      /*mov $0x4, %al*/
"\xb2\x08"      /*mov $0x8, %dl*/
"\xcd\x80"      /*int $0x80*/
"\xb0\x02"      /*xor %eax, %eax*/
"\x50"          /*pushl %eax*/
"\xb0\x02"      /*movb $2, %al*/
"\x50"          /*pushl %eax*/
"\x89\xe3"      /*movl %esp, %ebx*/
"\x31\xc9"      /*xor %ecx, %ecx*/
"\xb0\xa2"      /*mov $0xa2, %al*/
"\xcd\x80"      /*int $0x80*/
"\x31\xc0"      /*xor %eax, %eax*/
"\x8d\x76\x09"  /*leal 0x09(%esi),%esi*/
"\x50"          /*push %eax*/
"\x89\xf3"      /*mov %esi, %ebx*/
"\x8d\x76\x08"  /*lea 0x8(%esi), %esi*/
"\x56"          /*push %esi*/
"\x53"          /*push %ebx*/
"\xb0\x0b"      /*mov $0xb, %al*/
"\x89\xe1"      /*mov %esp, %ecx*/
"\x8d\x51\x04"  /*lea 0x4(%esp), %edx*/
"\xcd\x80"      /*int $0x80*/
"\x31\xdb"      /*xor %ebx, %ebx*/
"\x8d\x43\x01"  /*lea 0x1(%ebx), %eax*/
"\xcd\x80"      /*int $0x80*/
"\xe8\xc2\xff\xff\xff"  /*relative call*/
"Run Han!\x0"
"/bin/rm\x0"
"./test\x0"
"\x00\x00\x00\x00";

void main() {
   int *ret;
   ret = (int *)&ret + 2;
   (*ret) = (int)shellcode;

}
compile it , use execstack to enable the executable stack and execute it. After that you will see the program first print a message, wait about two seconds and remove a file called "test".

Jul 2, 2011

Shell code 4(another trick)

By far, the shell code can print a message and exit the program normally.
Now I add a new feature in the previous shell code program. That is let the program wait 2 seconds and then exit.

In order to do this, I need to use a new system call called "nanosleep". (my OS is ubuntu 10.10)
use the following command to see what nanosleep do:
man nonosleep
#include <time.h>
int nanosleep(const struct timespec *req, struct timespec *rem);
....
struct timespec {
               time_t tv_sec;        /* seconds */
               long   tv_nsec;       /* nanoseconds */
           };

P.S since I write a simple program to see the size of the timespec, and also the size of each fields. the time_t type is 4 bytes and long is 4 bytes, so the timespec is totally 8 bytes long.
Tips: you can write a C program that use the "sizeof()" MACRO to see the size of each type of variable.
The above are the information that I needed.

Now, as usual, write an inline assembly program.
sleep1.c

/*the time_spec structure*/
char t1_v[]="\x02\x00\x00\x00\x00\x00\x00\x00";
int main(){
        __asm__("movl $t1_v, %ebx;\
                 movl $0, %ecx;\
                 movl $162, %eax;\
                 int  $0x80;\
                 movl $1,%eax;\
                 movl $0,%ebx;\
                 int  $0x80;\
                 ");
        return 0;
}
Compile the source code and execute it, you will see that the program actually wait about 2 seconds then exit.
However, just like the previous post: Shell code 3(cont.) I don't want the data is outside the shell code. Therefore, I use the same trick, the relative jmp/call trick, mentioned in the previous post.
sleep2.c
int main(){
        /* relative jmp/call trick */
        __asm__("jmp 2f;\n\
                 1:;\n\
                 pop %esi;\n\
                 movl %esi, %ebx;\n\
                 movl $0, %ecx;\n\
                 movl $162, %eax;\n\
                 int  $0x80;\n\
                 movl $1,%eax;\n\
                 movl $0,%ebx;\n\
                 int  $0x80;\n\
                 2:;\n\
                 call 1b;\n\
                 .long 0x00000002,0x0;\n\
                 ");
        return 0;
} 
Compile the source code and test the result. (It works :D ) 
Instead of using relative jmp/call trick to get the address of the data, is there any other way to get the address too?
Why not just push the parameter to the stack, and the %esp will content the address of our data. Let's use this push trick to write our code.
sleep3.c
int main(){
        /* push trick */
        __asm__("push $0;\n\
                 push $2;\n\
                 movl %esp, %ebx;\n\
                 movl $0, %ecx;\n\
                 movl $162, %eax;\n\
                 int  $0x80;\n\
                 movl $1,%eax;\n\
                 movl $0,%ebx;\n\
                 int  $0x80;\n\               
                 ");
        return 0;
}
P.S remember that the stack grow down, therefore push the data in reverse order.
Before writing the shellcode, I add the write system call into the inline assembly.
sleep4.c
/*
 * In this example I use both the 
 * relative jmp/call trick and
 * push trick to get the data.
 */
int main(){
        __asm__("jmp 2f;\n\
                 1:;\n\
                 popl %esi;\n\
                 movl $4,%eax;\n\
                 movl $1,%ebx;\n\
                 movl $0x7,%edx;\n\
                 movl %esi,%ecx;\n\
                 int  $0x80;\n\
                 push $0;\n\
                 push $2;\n\
                 movl %esp, %ebx;\n\
                 movl $0, %ecx;\n\
                 movl $162, %eax;\n\
                 int  $0x80;\n\
                 movl $1,%eax;\n\
                 movl $0,%ebx;\n\
                 int  $0x80;\n\
                 2:;\n\
                 call 1b;\n\
                 .string "Run Han";\n\
                ");
        return 0;
}
This is how the inline assembly looks like, it is pretty big now.

Again, compile the source code and test the result. If everything is correct, you will see the message and wait about 2 seconds then exit the program.
If everything works fine, objdump the binary files.

Copy the machine code and paste into another source file as the shellcode.
sleep5.c
/* This is the shellcode */
/* This is the shellcode */
char shellcode[]=
"\xeb\x32"
"\x5e"
"\xb8\x04\x00\x00\x00"
"\xbb\x01\x00\x00\x00"
"\xba\x07\x00\x00\x00"
"\x89\xf1"
"\xcd\x80"
"\x6a\x00"
"\x6a\x02"
"\x89\xe3"
"\xb9\x00\x00\x00\x00"
"\xb8\xa2\x00\x00\x00"
"\xcd\x80"
"\xb8\x01\x00\x00\x00"
"\xbb\x00\x00\x00\x00"
"\xcd\x80"
"\xe8\xc9\xff\xff\xff"
"Run Han";
int main(){
        int *ptr;
        int i;
        /* 
         * overflow the return address
         * transfer the execution flow to shellcode
         */
        for(i=0;i<10;i++){
                ptr = (int*)&ptr+i;
                *(ptr) = (int)shellcode;
        }
        return 0;
}

Compile the source code and use execstack to enable the executable stack.
gcc -g -o sleep4.out sleep4.c
execstack -s sleep4.out
execute the program and check the result is what we expected.
Moreover, you can even use gdb to see the result.
Result: 

Jun 30, 2011

Simple OS - bootloader part1

The past few days, I've finished writing the bootloader. I summarize some of them and will post them on the blog.

Introduction:
Before we started writing our code, there are some background knowlege.


Bootloader:
what is a bootloader?
A bootloader is a program that will load the kernel image into the memory, and jumps to it.

how does it works?
First when you press the power bottom, the bios will start first. And after the bios is loaded into the memory,
it will first check which device you want to boot and check the first sector(The MBR) of the device. If it is OK, the bios will put the MBR code into the memory address 0x7c00 and jump to it.









MBR:
what is MBR?
MBR is the abbreviation of master boot record. As the name suggest the code inside the MBR is the bootloader. In most cases, the MBR is in the first sector of your devices, such as the hard disk, floopy disk , compact disk and so on.

The size of the MBR is 512 bytes. There are many fields contains in a MBR.
a. code                 440bytes
b. Disk signature   4 bytes.
c. null                   2 bytes
d. Partition tables. 64bytes
e. MBR signature 2 bytes.









BIOS interrupt:


what is bios interrupt?
bios interrupt is a low level interrupt which is loaded before the bootloader. BIOS interrupt contains many useful functions which can communicate with the I/O without fully understand the architecture.

why using bios interrupt?
as I previous mentioned, bootloader is to load the kernel image into the memory, and therefore there is no os system call or drivers to help you communicate with the I/O. The best way and the most convenient way is to use the bios interrupt to handle the I/O.

Coding time:
After understand the information, it's time to write a simple hello world program in the boot loader.
Helloworld.S
.code16
.section .text
.global main
main:
#FAT12 file system format
#there is nothing to change in this part
        jmp start_prog
        .byte   0x90
        .ascii  "MicrMike"
        .word   512
        .byte   1
        .word   1
        .byte   2
        .word   224
        .word   2880
        .byte   0xf0
        .word   9
        .word   18
        .word   2
        .long   0
        .long   2880
        .byte   0
        .byte   0
        .byte   0x29
        .long   0x19900303
        .ascii  "HELLO-OS   "
        .ascii  "FAT12   "
        .fill   18, 1, 0
start_prog:
        movw $0, %ax
        movw %ax, %ss
        movw %ax, %ds
        movw %ax, %es
        movw $msg, %si
#using bios interrupt 10h
#parameter of bios interrupt 10h
#%ah: function number
#%al: the offset of the message
loop:
        movb    $0xe, %ah
        movb    (%si), %al
        cmpb    $0, %al
        je      fin
        int     $0x10
        addw    $1, %si
        jmp     loop
fin:
        jmp     fin
msg:
        .ascii  "Hello world!!."
        .byte 0
        .org    0x1fe, 0x00
        .word   0xaa55
P.S the above source code is using the at&t syntax. In this article I won't tell you how to write assembly, but you can google to find some great tutorial.
Comment:
There are many things that is worth notice in the source code.
1. The red highlight is the FAT12 file system format. Do not change this part.
2. Since we are in the real mode and the ld will assume that the code is in 0x0, I need to initial the whole base register, such as ds, ss and so on.
3. In order to print a message on the screen, I use the bios interrupt.
    bios interrupt 10h
    %ah stores the function number, in this case use the $0xe.
    %al stores the address of the message.
4. in the bottom of the code, don't forget to put the MBR signature, otherwise the bios will think the MBR is     useless.


Compile:
1. use gcc to compile the source code:
  gcc -c Helloworld.S
2. use ld to link the obj file into the binary:
  ld -Ttext=0x0 --oformat binary Helloworld.o -o Helloworld.bin
3. use mkdosfs to create a virtual floppy disk
  mkdosfs -C os.flp 1440
4. install the binary file into the virtual floppy disk by using dd 
  dd status=noxfer conv=notrunc if=$boot_bin of=os.flp
reference website:

Result:
using qemu to test the result.
qemu -fda os.flp
and you will see a hello world in the qemu.
http://duartes.org/gustavo/blog/post/how-computers-boot-up

Jun 29, 2011

Shell code 3(print message)

After the exit_shell.out program is finished, it's time to move on.
This time I will use a new system call which will print a message to the screen.

Background Knowlege:
the way I use the system call is still the same, using the int $0x80.
The parameters of print system call:
eax = 4  => this is the system call number.
ebx = 1  => we want to print the message to the stdout.
ecx =  msg => the address of the message.
edx = len   => the length of the message.

OK, coding time.
1.wrote the program into inline assembly.
print.c
char msg[]="Run Han";
int main(){
        __asm__("
                 movl $4,%eax;\
                 movl $1,%ebx;\
                 movl $0x7,%edx;\
                 movl $msg,%ecx;\
                 int  $0x80;\
                 movl $1,%eax;\
                 movl $0,%ebx;\
                 int  $0x80;\
                 ");
        return 0;
}
2.compile the source code with the following command:
gcc -g -o print.out print.c
3. execute the program

As u can see, the output message is in the global data, that's not good. I want the message is inside the shell code. Let's modified the source code a bit.
print_1.c
int main(){
        __asm__("
                 movl $4,%eax;\
                 movl $1,%ebx;\
                 movl $0x7,%edx;\
                 movl $msg,%ecx;\
                 int  $0x80;\
                 movl $1,%eax;\
                 movl $0,%ebx;\
                 int  $0x80;\
                 .string "Run Han"\
                 ");
        return 0;
}

However, in this way, how do I know the address of the message.
Thanks to this web site: http://insecure.org/stf/smashstack.html
I found the solution. The following is the modified version of the code.
print_2.c
int main(){
        __asm__("jmp 2f;\n\                   #2bytes
                 1:;\n\
                 popl %esi;\n\                #1bytes
                 movl $4,%eax;\n\             #5bytes
                 movl $1,%ebx;\n\             #5bytes
                 movl $0x7,%edx;\n\           #5bytes
                 movl %esi,%ecx;\n\           #2bytes
                 int  $0x80;\n\               #2bytes
                 movl $1,%eax;\n\             #5bytes
                 movl $0,%ebx;\n\             #5bytes
                 int  $0x80;\n\               #2bytes
                 2:;\n\
                 call 1b;\n\                  #5bytes
                 .string "Run Han";\n\
                 ");
        return 0;
}
Explanation:
Use the relative jmp/call to accomplish this job.
1. we first use the relative jump to jump to the call instruction.
2. next we use the relative call instruction to transfer the execution flow to the label 1.

So how does these steps has anything to do with the address of the message.
This is a very tricky way. When u call a function, the cpu will automatically push the eip into the stack. And look what is behind the call function, it is the message. So the cpu will help us to push the address of the message to the stack.

And now let's compile the file, and test the output.
It works.

The next step is much easier than above, all I have to do is use the objdump to dump the file, and change the inline assembly into shell code.

print_shell.c
char shellcode[]=
"\xeb\x20"
"\x5e"
"\xb8\x04\x00\x00\x00"
"\xbb\x01\x00\x00\x00"
"\xba\x07\x00\x00\x00"
"\x89\xf1"
"\xcd\x80"
"\xb8\x01\x00\x00\x00"
"\xbb\x00\x00\x00\x00"
"\xcd\x80"
"\xe8\xdb\xff\xff\xff"
"Run Han";
int main(){
        int *ptr;
        int i;
        /*
         *overflow the return address.
         *transfer the execution flow to shellcode.
         */
        for(i=0;i<10;i++){
                ptr = (int*)&ptr+i;
                *(ptr) = (int)shellcode;
        }
        return 0;
}
compile the program and don't forget to use the execstack command to enable the executable stack.
demo video:
http://www.youtube.com/watch?v=WpfShXa1iEk



Labels