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

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.

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.

Position Independent Code pointing to wrong address

I have a small example program written in NASM(2.11.08) targeting the macho64 architecture. I'm running OSX 10.10.3:
bits 64
section .data
msg1 db 'Message One', 10, 0
msg1len equ $-msg1
msg2 db 'Message Two', 10, 0
msg2len equ $-msg2
section .text
global _main
extern _printf
_main:
sub rsp, 8 ; align
lea rdi, [rel msg1]
xor rax, rax
call _printf
lea rdi, [rel msg2]
xor rax, rax
call _printf
add rsp, 8
ret
I'm compiling and linking using the following command line:
/usr/local/bin/nasm -f macho64 test2.s
ld -macosx_version_min 10.10.0 -lSystem -o test2 test2.o
When I do an object dump on the test2 executable, this is the relevant snippet(I can post more if I'm wrong!):
0000000000001fb7 <_main>:
1fb7: 48 83 ec 08 sub $0x8,%rsp
1fbb: 48 8d 3d 56 01 00 00 lea 0x156(%rip),%rdi # 2118 <msg2+0xf3>
1fc2: 48 31 c0 xor %rax,%rax
1fc5: e8 14 00 00 00 callq 1fde <_printf$stub>
1fca: 48 8d 3d 54 00 00 00 lea 0x54(%rip),%rdi # 2025 <msg2>
1fd1: 48 31 c0 xor %rax,%rax
1fd4: e8 05 00 00 00 callq 1fde <_printf$stub>
1fd9: 48 83 c4 08 add $0x8,%rsp
1fdd: c3 retq
...
0000000000002018 <msg1>:
0000000000002025 <msg2>:
And, finally, the output:
$ ./test2
Message Two
$
My question is, what happened to msg1?
I'm assuming msg1 isn't printed because 0x14f(%rip) is not the correct address (just nulls).
Why is lea edi, [rel msg2] pointing to the correct address, while lea edi, [rel msg1] is pointing past msg2, into NULLs?
It looks like the 0x14f(%rip) offset is exactly 0x100 beyond where msg1 lies in memory (this is true throughout many tests of this problem).
What am I missing here?
Edit: Whichever message (msg1 or msg2) appears last in the .data section is the only message that gets printed.
IDK about the Mach-o ABI, but if it's the same as the SystemV x86-64 ABI GNU/Linux uses, then I think your problem is that you need to clear eax to tell a varargs function like printf that there are zero FP.
Also, lea rdi, [rel msg1] would be a much better choice. As it stands, your code is only position-independent within the low 32bits of virtual address space, because you're truncating the pointers to 32bits.
It appears NASM has a bug. This same problem came up again: NASM 2 lines of db (initialized data) seemingly not working. There, the OP confirmed that the data was present, but labels were wrong, and is hopefully reporting it upstream.

Segmentation Fault happening before any code is run Assembly

I am trying to write a shell code program that will call execve and spawn a shell. I am working in a 32 bit virtual machine that was offered for this class. The code is as follows:
section .text
global _start
_start:
;clear out registers
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
;exacve("/bin/sh",Null,NULL)
;ascii for /bin/sh;
;2f 62 9 6e 2f 73 68 3b
push 0x3b68732f
push 0x6e69622f
mov ebx, esp
mov al, 11
int 0x80
;exit(int status)
movv al, 1
xor ebx, ebx
int 0x80
I compile with nasm -f elf -g shell.asm and link with ld -o shell shell.o
When I try to run it, I get a segmentation fault. I tried using gdb to see where I made the mistake, but, it segfaults even if a set a break point at _start+0. It says that there was a segfault at the address after the last instruction for the code.
i.e. if The last line has an address of 0x804807c then the segmentation fault happens at 0x804807e before any of the code has a chance to run.
Could any one point me in the right direction so I can figure out how to fix this?
One mistake in your code is, that there is no 0x3b in ascii code of the string:
;exacve("/bin/sh",Null,NULL)
;ascii for /bin/sh;
;2f 62 9 6e 2f 73 68 3b
push 0x3b68732f
push 0x6e69622f
This following code shall fix this problem (assuming you do work with a little-endian machine):
;exacve("/bin/sh",Null,NULL)
;ascii for /bin/sh;
;2f 62 99 6e 2f 73 68 00
push 0x0068732f
push 0x6e69622f

How can I check the commands the given shellcode executes?

Lets say I'm given the following shellcode:
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80";
How can I check what it means / the ASM instructions it represents?
Thanks :)
Compile and disassemble it! For your example:
$ cat example.c
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80";
$ make example.o
cc -c -o example.o example.c
$ objdump -D example.o
example.o: file format elf64-x86-64
Disassembly of section .data:
0000000000000000 <shellcode>:
0: 31 c0 xor %eax,%eax
2: 31 db xor %ebx,%ebx
4: 31 c9 xor %ecx,%ecx
6: 99 cltd
7: b0 a4 mov $0xa4,%al
9: cd 80 int $0x80
b: 6a 0b pushq $0xb
d: 58 pop %rax
e: 51 push %rcx
f: 68 2f 2f 73 68 pushq $0x68732f2f
14: 68 2f 62 69 6e pushq $0x6e69622f
19: 89 e3 mov %esp,%ebx
1b: 51 push %rcx
1c: 89 e2 mov %esp,%edx
1e: 53 push %rbx
1f: 89 e1 mov %esp,%ecx
21: cd 80 int $0x80
...
Note the use of objdump's -D flag to disassemble all sections, rather than just what it thinks the executable sections are.
As for what this code means, I guess we can break it down piece by piece (from above, with inline comments):
xor %eax,%eax // clear eax register
xor %ebx,%ebx // clear ebx register
xor %ecx,%ecx // clear ecx register
cltd // clear edx register (via sign-extension of eax
// - only a compiler would do this operation
// in this way, I'd guess, so your shell code
// probably wasn't hand-written
mov $0xa4,%al // put 0xa4 (decimal 164) into eax
int $0x80 // do system call. Syscall 164 is "sys_setresuid"
// - it takes three parameters, in ebx, ecx, and edx,
// so in this case, it's calling sys_setresuid(0, 0, 0);
pushq $0xb // push constant 0xb (decimal 11) to the stack
pop %rax // pop it back into rax
push %rcx // push the 0 in rcx to the stack
pushq $0x68732f2f // push constant to the stack (looks like ASCII? "//sh")
pushq $0x6e69622f // push constant to the stack (looks like ASCII? "/bin")
mov %esp,%ebx // put a pointer to this stack pushed stuff into ebx
push %rcx // push rcx again, it's still 0
mov %esp,%edx // put a pointer to this 0 on the stack into edx
push %rbx // push rbx, it's 0 too
mov %esp,%ecx // put a pointer to this 0 into ecx
int $0x80 // system call again - this time, it's call 11, which is
// sys_execve. It takes a pointer to a filename to execute
// and two more pointers to the arguments and environment to
// pass
So this code first calls:
sys_setresuid(0, 0, 0)
To give itself root privileges, and then calls sys_execve() to start running /bin/sh, giving a shell prompt.

x86 assembly, little endianness not being followed(or is it?) (Linux)

I am new to assembly language programming and I wrote a small program to print the integer using sys_write system call. Here's my code :
section .data
N: dw 216
chr: dw ,0,0,0,0x0a
section .bss
section .text
global _start
_start:
xor ax, ax
mov ax, word [N]
mov cx, 10
mov ebx,4
shift_while: div cx
add dx, 0x0030
mov word [chr+ebx],dx
sub ebx, 2
xor dx, dx
cmp ax, 0
jne shift_while
call printchar
exit: mov eax, 1
mov ebx, 0
int 80h
printchar: pushad
mov eax, 4
mov ebx, 1
mov ecx, chr
mov edx, 8
int 80h
popad
ret
I have hard coded 216, the number to be printed and I am getting the correct output. However what I am bemused by is the "mov word [chr+ebx],dx" instruction. dx contains 0x0032 in the first iteration so at the address [chr+ebx] this value should be stored as
32 00 (hex). But when I examined chr memory using gdb, it showed:
(gdb) x /5hx 0x80490d2
0x80490d2 <chr>: 0x0032 0x0031 0x0036 0x000a
what I expected was 0x3200 0x3100 0x3600 x0a00 and thought I'd have to do further memory manipulation to get the right result.
Am I going wrong somewhere with this. Are there things I can't seem to see. I'd really appreciate a little help here. This is my first first post on stackoverflow.
It's just a representation thing - what you have in memory from a byte-wise perspective is
32 00 31 00 26 00 0a 00
but when you view this as 16 bit values it's
0032 0031 0026 000a
Similarly, if you viewed it as 32 bit values it would be:
00310032 000a0026
Such is the weirdness of little endianness. ;-)
gdb is helping you out here.
You asked for the h (halfword) format, on a little-endian platform, so it is decoding the memory as 16-bit little endian-values for you.
If you use the b format instead, you'll see something more like you expected.

Resources