Passing arguments to execve(2) via registers - linux

I have wrote a short program to execute a bash using execve(2).
my_prog.c
int main(){
execve(Argument_1,Argument_2,NULL);
}
Here is the disassembly of execve(2) [neglecting the main assembly for simplicity]
(gdb) disassemble execve
Dump of assembler code for function execve:
0xf7ea77e0 <+0>: push ebx
0xf7ea77e1 <+1>: mov edx,DWORD PTR [esp+0x10]
0xf7ea77e5 <+5>: mov ecx,DWORD PTR [esp+0xc]
0xf7ea77e9 <+9>: mov ebx,DWORD PTR [esp+0x8]
0xf7ea77ed <+13>: mov eax,0xb
0xf7ea77f2 <+18>: call DWORD PTR gs:0x10
0xf7ea77f9 <+25>: pop ebx
0xf7ea77fa <+26>: cmp eax,0xfffff001
0xf7ea77ff <+31>: jae 0xf7e0f730
0xf7ea7805 <+37>: ret
I found the arguments to execv(2) in the following registers
eax --> index of execve(2) in syscall table
ebx --> Argument_2
ecx --> Argument_3
and Argument_1 on the top of the stack
(gdb) x/xw $esp
0xffffce00: 0x080484ea
(gdb) x/s 0x080484ea
0x80484ea: "/bin/bash" <--- Argument_1
The edx contains 0x080484ab
(gdb) x/xw 0x080484ab
0x80484ab <__libc_csu_init+75>: 0x8301c783
(gdb) x/xw 0x8301c783
0x8301c783: Cannot access memory at address 0x8301c783
I am on linux-intel(x86) system, so i assume that all parameters to execve(2) should be passed via registers but i couldn't found Argument_1 in any register though it is present on the stack.

I'm stopped at the first instruction of execve module.
execve is not a "module", it's a libc function, which loads arguments into registers, and then performs the actual system call.
i couldn't found Argument_1 in any register
If you stopped on instruction at address 0xf7ea77f2, you would.
But you are stopped on entry into a C function execve, so the arguments are where a C function expects them. On i*86, the arguments are passed on the stack, so that's where you'll find them: x/3wx $esp is what you want (at that point in the program).

Related

Why does my shellcode segfault when executed from C, but not as a stand-alone executable?

I'm trying to execute a shell with shellcode. I've made this code in a 64-bits machine:
section .text
global _start
_start:
xor rax, rax
push rax
mov rbx, "/bin//sh"
push rbx
mov rdi, rsp
mov al, 59
syscall
mov al, 60
xor rdi, rdi
syscall
After using nasm and linking with ld if i execute the file this works fine. The problem is if i get the shellcode from this and tried to execute it with this program:
int main(){
char *shellcode = "\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\xb0\x3b\x0f\x05\xb0\x3c\x48\x31\xff\x0f\x05";
(*(void(*)()) shellcode)();
}
It gives me a segmentation fault error. I can't see what's wrong here. Any help would be appreciated.
EDIT: Already tried the gcc -z execstack to make the stack executable, still gives a segmentation fault error
It is normal, because your shellcode is not setting the registers rsi and rdx, and when your C program executes the shellcode will have garbage in the registers rdi and rdx. It is because the syscall execve needs more arguments.
int execve (const char *filename, const char *argv [], const char *envp[]);
As extra information, the segmentation fault is because after your execve syscall you will get an error in rax and you will move 60 to the last 8 bits of rax and call to this syscall that doesn't exist.

Basic nasm shellcode crashes

I'm learning assembly, so I'm working on shellcode. I wrote a simple "hello world" program in nasm, but it crashes when run.
; write.asm
[SECTION .text]
global _start
_start:
jmp short message;
write: ; takes two arguments pushed onto stack -> text, textlen
pop edx ; pop length into edx
pop ecx ; pop ptr to text into ecx
pushad
mov al, 4
mov bl, 1
int 80h ; syscall
popad
ret
exit: ; push exit_code onto stack
mov al, 1
pop ebx ; pop exit_code into ebx
int 80h
main:
pop eax ; pop ptr to message into eax
push 7 ; length of string
push eax ; push ptr to message
call write
xor ebx, ebx; zero out ebx
push ebx
call exit
message:
call main
db 'Hello!', 10
I compile it with:
nasm -f elf write.asm
ld -m elf_i386 -o write write.o
and get this:
Segmentation fault (core dumped)
I tried debugging it with gdb, but it didn't help.
I would like to show to you, how you could find your problem by using gdb:
Start gdb and load your program: >> gdb write
Set breakpoint directly at start: (gdb) b _start.You could just let the program run until segfault, but if the stack is messed up, the chances are high you will not see anything.
Set up the display to show 5 top values on the stack automatically after every step: (gdb) display/x {unsigned int[5]}$sp
To see the next executed line: (gdb) display/i $pc
Now run: (gdb) run
Debugger hits the breakpoint and you see the stack set up by the system:
1: /x {unsigned int[5]}$sp = {0x1, 0xffffd284, 0x0, 0xffffd29d, 0xffffd2b2}
Everything Ok so far, the program was started with one argument (0x1 on the top) - the path to the program (you can see it by (gdb) print (char[10])*(0xffffd284)).
make a step (gdb) si, now we jumped to the message symbol.
With (gdb) disas one can see more of the code:
(gdb) disas
Dump of assembler code for function message:
=> 0x08048083 <+0>: call 0x8048072 <main>
0x08048088 <+5>: dec %eax
0x08048089 <+6>: gs
0x0804808a <+7>: insb (%dx),%es:(%edi)
0x0804808b <+8>: insb (%dx),%es:(%edi)
0x0804808c <+9>: outsl %ds:(%esi),(%dx)
0x0804808d <+10>: and %ecx,(%edx)
End of assembler dump.
As you can see, your "Hello"-string is interpreted as operations beginning at 0x08048088
make another step: (gdb) si, going into the function main.
Now take a look at the stack:
1: /x {unsigned int[5]}$sp = {0x8048088, 0x1, 0xffffd283, 0x0, 0xffffd29c}
The call-instruction pushed the return address on the stack - 0x08048088 - the address of your string. Nice trick, let's hope main will never return...
let's fast forward to the call of write: (gdb) si 3 and go inside (gdb) si.
Let's look at the stack, as expected, call added the return address to the stack:
1: /x {unsigned int[5]}$sp = {0x804807b, 0x8048088, 0x7, 0x1, 0xffffd283}
Your program expects the pointer to the string and the length to be on top, but this is not the case.
Lets fast forward to the return of the function write: (gdb) si 7.
Take a look at the stack:
1: /x {unsigned int[5]}$sp = {0x7, 0x1, 0xffffd283, 0x0, 0xffffd29c}
the next operation - ret will pop 0x7 from the stack and try to assume the execution at the address 0x7 which results in a segfault (as rcd suspected).
So your problem is that your functions corrupt the stack. Normally, the function setting up the stack for a call is also responsible for cleaning it up afterwards.

I'm getting a segmentation fault in my assembly program [duplicate]

The tutorial I am following is for x86 and was written using 32-bit assembly, I'm trying to follow along while learning x64 assembly in the process. This has been going very well up until this lesson where I have the following simple program which simply tries to modify a single character in a string; it compiles fine but segfaults when ran.
section .text
global _start ; Declare global entry oint for ld
_start:
jmp short message ; Jump to where or message is at so we can do a call to push the address onto the stack
code:
xor rax, rax ; Clean up the registers
xor rbx, rbx
xor rcx, rcx
xor rdx, rdx
; Try to change the N to a space
pop rsi ; Get address from stack
mov al, 0x20 ; Load 0x20 into RAX
mov [rsi], al; Why segfault?
xor rax, rax; Clear again
; write(rdi, rsi, rdx) = write(file_descriptor, buffer, length)
mov al, 0x01 ; write the command for 64bit Syscall Write (0x01) into the lower 8 bits of RAX
mov rdi, rax ; First Paramter, RDI = 0x01 which is STDOUT, we move rax to ensure the upper 56 bits of RDI are zero
;pop rsi ; Second Parameter, RSI = Popped address of message from stack
mov dl, 25 ; Third Parameter, RDX = Length of message
syscall ; Call Write
; exit(rdi) = exit(return value)
xor rax, rax ; write returns # of bytes written in rax, need to clean it up again
add rax, 0x3C ; 64bit syscall exit is 0x3C
xor rdi, rdi ; Return value is in rdi (First parameter), zero it to return 0
syscall ; Call Exit
message:
call code ; Pushes the address of the string onto the stack
db 'AAAABBBNAAAAAAAABBBBBBBB',0x0A
This culprit is this line:
mov [rsi], al; Why segfault?
If I comment it out, then the program runs fine, outputting the message 'AAAABBBNAAAAAAAABBBBBBBB', why can't I modify the string?
The authors code is the following:
global _start
_start:
jmp short ender
starter:
pop ebx ;get the address of the string
xor eax, eax
mov al, 0x20
mov [ebx+7], al ;put a NULL where the N is in the string
mov al, 4 ;syscall write
mov bl, 1 ;stdout is 1
pop ecx ;get the address of the string from the stack
mov dl, 25 ;length of the string
int 0x80
xor eax, eax
mov al, 1 ;exit the shellcode
xor ebx,ebx
int 0x80
ender:
call starter
db 'AAAABBBNAAAAAAAABBBBBBBB'0x0A
And I've compiled that using:
nasm -f elf <infile> -o <outfile>
ld -m elf_i386 <infile> -o <outfile>
But even that causes a segfault, images on the page show it working properly and changing the N into a space, however I seem to be stuck in segfault land :( Google isn't really being helpful in this case, and so I turn to you stackoverflow, any pointers (no pun intended!) would be appreciated
I would assume it's because you're trying to access data that is in the .text section. Usually you're not allowed to write to code segment for security. Modifiable data should be in the .data section. (Or .bss if zero-initialized.)
For actual shellcode, where you don't want to use a separate section, see Segfault when writing to string allocated by db [assembly] for alternate workarounds.
Also I would never suggest using the side effects of call pushing the address after it to the stack to get a pointer to data following it, except for shellcode.
This is a common trick in shellcode (which must be position-independent); 32-bit mode needs a call to get EIP somehow. The call must have a backwards displacement to avoid 00 bytes in the machine code, so putting the call somewhere that creates a "return" address you specifically want saves an add or lea.
Even in 64-bit code where RIP-relative addressing is possible, jmp / call / pop is about as compact as jumping over the string for a RIP-relative LEA with a negative displacement.
Outside of the shellcode / constrained-machine-code use case, it's a terrible idea and you should just lea reg, [rel buf] like a normal person with the data in .data and the code in .text. (Or read-only data in .rodata.) This way you're not trying execute code next to data, or put data next to code.
(Code-injection vulnerabilities that allow shellcode already imply the existence of a page with write and exec permission, but normal processes from modern toolchains don't have any W+X pages unless you do something to make that happen. W^X is a good security feature for this reason, so normal toolchain security features / defaults must be defeated to test shellcode.)

Difference in behaviour between code executed by a pthread and the main thread in x64-assembly

When writing some x64 assembly, I stumbled upon something weird. A function call works fine when executed on a main thread, but causes a segmentation fault when executed as a pthread. At first I thought I was invalidating the stack, as it only segfaults on the second call, but this does not match with the fact that it works properly on the main thread yet crashes on a newly-spawned thread.
From gdb:
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Value: 1337
Value: 1337
[New Thread 0x7ffff77f6700 (LWP 8717)]
Return value: 0
Value: 1337
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff77f6700 (LWP 8717)]
__printf (format=0x600570 <fmt> "Value: %d\n") at printf.c:28
28 printf.c: No such file or directory.
Does anyone have an idea about what could be going on here?
extern printf
extern pthread_create
extern pthread_join
extern pthread_exit
section .data
align 4
fmt db "Value: %d", 0x0A, 0
fmt_rval db "Return value: %d", 0x0A, 0
tID dw 0
section .text
global _start
_start:
mov rdi, 1337
call show_value
call show_value ; <- this call works fine
; CREATE THREAD
mov ecx, 0 ; function argument
mov edx, thread_1 ; function pointer
mov esi, 0 ; attributes
mov rdi, tID ; pointer to threadID
call pthread_create
mov rdi, rax
call show_rval
mov rsi, 0 ; return value
mov rdi, [tID] ; id to wait on
call pthread_join
mov rdi, rax
call show_rval
call exit
thread_1:
mov rdi, 1337
call show_value
call show_value ; <- this additional call causes a segfault
ret
show_value:
push rdi
mov rsi, rdi
mov rdi, fmt
call printf
pop rdi
ret
show_rval:
push rdi
mov rsi, rdi
mov rdi, fmt_rval
call printf
pop rdi
ret
exit:
mov rax, 60
mov rdi, 0
syscall
The binary was generated on Ubuntu 14.04 (64-bit of course), with:
nasm -felf64 -g -o $1.o $1.asm
ld -I/lib64/ld-linux-x86-64.so.2 -o $1.out $1.o -lc -lpthread
Functions that take a variable number of parameters like printf require the RAX register to be set properly. You need to set it to the number of vector registers used, which in your case is 0. From Section 3.2.3 Parameter Passing in the System V 64-bit ABI:
RAX
temporary register;
with variable arguments passes information about the number of vector registers used;
1st return register
Section 3.5.7 contains more detailed information about the parameter passing mechanism of functions taking a variable number of arguments. That section says:
When a function taking variable-arguments is called, %rax must be set to the total number of floating point parameters passed to the function in vector registers.
Modify your code to set RAX to zero in your call to printf:
show_value:
push rdi
xor rax, rax ; rax = 0
mov rsi, rdi
mov rdi, fmt
call printf
pop rdi
ret
You have a similar issue with show_rval
One other observation is that you could simplify linking your executable by using GCC instead of LD
I would recommend renaming _start to main and simply use GCC to link the final executable. GCC's C runtime code will provide a _start label that does proper initialization of the C runtime, which could potentially be required in some scenarios. When the C runtime code is finished initialization it transfers (via a CALL) to the label main. You could then produce your executable with:
nasm -felf64 -g -o $1.o $1.asm
gcc -o $1.out $1.o -lpthread
I don't think this is related to your problem, but was meant more as an FYI.
By not properly setting RAX for the printf call, unwanted behavior may occur in some cases. In this case, the value of RAX not being set properly for the printf call in an environment with threads causes a segmentation fault. The code without threads happened to work because you were lucky.

Can anyone help me understand this asm code (It's short)

I'm trying to learn shellcode for a project
in comp science
but I’m having a bit of a problem writing it
I’m reading a book called The Shellcoder's Handbook
and it gives me a code that wont work properly
This is the code:
section .text
global _start
_start:
jmp short GotoCall
shellcode:
pop rsi
xor rax, rax
mov byte [rsi + 7], al
lea rbx, [rsi]
mov [rsi + 8], rbx
mov [rsi + 14], rax
mov byte al, 0x0b
mov rbx, rsi
lea rcx, [rsi + 8]
lea rdx, [rsi + 14]
int 0x80
GotoCall:
Call shellcode
db '/bin/shJAAAAAAKKKKKK'
simply put this is supposed to spawn a shell...
but it wont work and when i use gdb to debug it
i get a weird code and a segmentation fault error at
mov byte [rsi + 7], al
this is the gdb output:
gdb ./sclivro
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400085 in _start ()
(gdb) disas _start
Dump of assembler code for function _start:
0x0000000000400080 <_start+0>: jmp 0x4000a2 <_start+34>
0x0000000000400082 <_start+2>: pop %rsi
0x0000000000400083 <_start+3>: xor %rax,%rax
0x0000000000400085 <_start+5>: mov %al,0x7(%rsi)
0x0000000000400088 <_start+8>: lea (%rsi),%rbx
0x000000000040008b <_start+11>: mov %rbx,0x8(%rsi)
0x000000000040008f <_start+15>: mov %rax,0xe(%rsi)
0x0000000000400093 <_start+19>: mov $0xb,%al
0x0000000000400095 <_start+21>: mov %rsi,%rbx
0x0000000000400098 <_start+24>: lea 0x8(%rsi),%rcx
0x000000000040009c <_start+28>: lea 0xe(%rsi),%rdx
0x00000000004000a0 <_start+32>: int $0x80
0x00000000004000a2 <_start+34>: callq 0x400082 <_start+2>
0x00000000004000a7 <_start+39>: (bad)
0x00000000004000a8 <_start+40>: (bad)
0x00000000004000a9 <_start+41>: imul $0x414a6873,0x2f(%rsi),%ebp
0x00000000004000b0 <_start+48>: rex.B
0x00000000004000b1 <_start+49>: rex.B
0x00000000004000b2 <_start+50>: rex.B
0x00000000004000b3 <_start+51>: rex.B
0x00000000004000b4 <_start+52>: rex.B
0x00000000004000b5 <_start+53>: rex.WXB
0x00000000004000b6 <_start+54>: rex.WXB
0x00000000004000b7 <_start+55>: rex.WXB
0x00000000004000b8 <_start+56>: rex.WXB
0x00000000004000b9 <_start+57>: rex.WXB
0x00000000004000ba <_start+58>: rex.WXB add %bpl,(%r14)
End of assembler dump.
I compile the code using yasm and ld
yasm -f elf64 sclivro.asm
ld -o sclivro sclivro.o
My OS is Debian 6.0 x64
I have a Intel Celeron processor
I wanted to know why am I getting a seg fault error
and explain to me.
Thanks for your time.
Also the book tells me to follow these steps:
Fill EAX with nulls by xoring EAX with itself.
Terminate our /bin/sh string by copying AL over the last byte of the
string. Remember that AL is null because we nulled out EAX in the previ-
ous instruction. You must also calculate the offset from the beginning of
the string to the J placeholder.
Get the address of the beginning of the string, which is stored in ESI,
and copy that value into EBX.
Copy the value stored in EBX, now the address of the beginning of the
string, over the AAAA placeholders. This is the argument pointer to the
binary to be executed, which is required by execve. Again, you need to
calculate the offset.
Copy the nulls still stored in EAX over the KKKK placeholders, using the
correct offset.
EAX no longer needs to be filled with nulls, so copy the value of our
execve syscall (0x0b) into AL.
Load EBX with the address of our string.
Load the address of the value stored in the AAAA placeholder, which is a
pointer to our string, into ECX.
Load up EDX with the address of the value in KKKK, a pointer to null.
Execute int 0x80.
The shellcode you've posted is for Linux running on a 32bit x86 processor - as can be seen from the use of "int 0x80" as system call instruction.
You've compiled it in 64bit mode, though, and attempted to run that. Which fails at the first memory access, because you're not using the real address of the "/bin/sh" string (which is in RSI) but only the explicitly truncated lower 32bit of it (since your code explicitly stated ESI). The latter is invalid, in 64bit mode, where your stack is somewhere at the upper end 0xffff....(64bit addr) of the address space.
The pop rsi instruction is getting the address of the string.
You are overwriting a write protected area when you try to put the nul byte after /bin/sh. I'm not sure why this code is supposed to be special: IT just looks like an obfuscated call to execve().

Resources