来自可利用程序的 运行 时出现 Shellcode Segmentation Fault 错误
Shellcode Segmentation Fault error when run from exploitable program
BITS 64
section .text
global _start
_start:
jmp short two
one:
pop rbx
xor al,al
xor cx,cx
mov al,8
mov cx,0755
int 0x80
xor al,al
inc al
xor bl,bl
int 0x80
two:
call one
db 'H'`
这是我的汇编代码。
然后我使用了两个命令。 "nasm -f elf64 newdir.s -o newdir.o" 和 "ld newdir.o -o newdir".I 运行 ./newdir 并且工作正常但是当我提取操作代码并尝试使用以下 c 程序测试此 shellcode 时。它不工作(没有分段错误)。我已经使用 cmd gcc newdir -z execstack
进行了编译
#include <stdio.h>
char sh[]="\xeb\x16\x5b\x30\xc0\x66\x31\xc9\xb0\x08\x66\xb9\xf3\x02\xcd\x80\x30\xc0\xfe\xc0\x30\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x48";
void main(int argc, char **argv)
{
int (*func)();
func = (int (*)()) sh;
(int)(*func)();
}
objdump -d newdir
newdir: file format elf64-x86-64
Disassembly of section .text:
0000000000400080 <_start>:
400080: eb 16 jmp 400098 <two>
0000000000400082 <one>:
400082: 5b pop %rbx
400083: 30 c0 xor %al,%al
400085: 66 31 c9 xor %cx,%cx
400088: b0 08 mov [=13=]x8,%al
40008a: 66 b9 f3 02 mov [=13=]x2f3,%cx
40008e: cd 80 int [=13=]x80
400090: 30 c0 xor %al,%al
400092: fe c0 inc %al
400094: 30 db xor %bl,%bl
400096: cd 80 int [=13=]x80
0000000000400098 <two>:
400098: e8 e5 ff ff ff callq 400082 <one>
40009d: 48 rex.W
当我 运行 ./a.out 时,我得到了照片中的东西。我附上照片是因为我无法解释发生了什么。image
P.S- 我的问题已经解决了。但我想知道哪里出了问题。所以我使用了调试器,结果如下
`
(gdb) list
1 char shellcode[] = "\xeb\x16\x5b\x30\xc0\x66\x31\xc9\xb0\x08\x66\xb9\xf3\x02\xcd\x80\x30\xc0\xfe\xc0\x30\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x48";
2 int main (int argc, char **argv)
3 {
4 int (*ret)();
5 ret = (int(*)())shellcode;
6
7 (int)(*ret)();
8 } (gdb) disassemble main
Dump of assembler code for function main:
0x00000000000005fa <+0>: push %rbp
0x00000000000005fb <+1>: mov %rsp,%rbp
0x00000000000005fe <+4>: sub [=14=]x20,%rsp
0x0000000000000602 <+8>: mov %edi,-0x14(%rbp)
0x0000000000000605 <+11>: mov %rsi,-0x20(%rbp)
0x0000000000000609 <+15>: lea 0x200a20(%rip),%rax # 0x201030 <shellcode>
0x0000000000000610 <+22>: mov %rax,-0x8(%rbp)
0x0000000000000614 <+26>: mov -0x8(%rbp),%rdx
0x0000000000000618 <+30>: mov [=14=]x0,%eax
0x000000000000061d <+35>: callq *%rdx
0x000000000000061f <+37>: mov [=14=]x0,%eax
0x0000000000000624 <+42>: leaveq
0x0000000000000625 <+43>: retq
End of assembler dump.
(gdb) b 7
Breakpoint 1 at 0x614: file test.c, line 7.
(gdb) run
Starting program: /root/Desktop/Progs/shell/a.out
Breakpoint 1, main (argc=1, argv=0x7fffffffe2b8) at test.c:7
7 (int)(*ret)();
(gdb) info registers rip
rip 0x555555554614 0x555555554614 <main+26>
(gdb) x/5i $rip
=> 0x555555554614 <main+26>: mov -0x8(%rbp),%rdx
0x555555554618 <main+30>: mov [=14=]x0,%eax
0x55555555461d <main+35>: callq *%rdx
0x55555555461f <main+37>: mov [=14=]x0,%eax
0x555555554624 <main+42>: leaveq
(gdb) s
(Control got stuck here, so i pressed ctrl+c)
^C
Program received signal SIGINT, Interrupt.
0x0000555555755048 in shellcode ()
(gdb) x/5i 0x0000555555755048
=> 0x555555755048 <shellcode+24>: callq 0x555555755032 <shellcode+2>
0x55555575504d <shellcode+29>: rex.W add %al,(%rax)
0x555555755050: add %al,(%rax)
0x555555755052: add %al,(%rax)
0x555555755054: add %al,(%rax)
这里是调试信息。我找不到控件的位置 wrong.If 需要更多信息请询问。
下面是一个使用 x86-64 的工作示例;可以进一步优化大小。最后一个 0x00 null 可以用于执行 shellcode。
assemble & link:
$ nasm -felf64 -g -F dwarf pushpam_001.s -o pushpam_001.o && ld pushpam_001.o -o pushpam_001
代码:
BITS 64
section .text
global _start
_start:
jmp short two
one:
pop rdi ; pathname
xor rax, rax
add al, 85 ; creat syscall 64-bit Linux
xor rsi, rsi
add si, 0755 ; mode - octal
syscall
xor rax, rax
add ax, 60
xor rdi, rdi
syscall
two:
call one
db 'H',0
objdump:
pushpam_001: file format elf64-x86-64
0000000000400080 <_start>:
400080: eb 1c jmp 40009e <two>
0000000000400082 <one>:
400082: 5f pop rdi
400083: 48 31 c0 xor rax,rax
400086: 04 55 add al,0x55
400088: 48 31 f6 xor rsi,rsi
40008b: 66 81 c6 f3 02 add si,0x2f3
400090: 0f 05 syscall
400092: 48 31 c0 xor rax,rax
400095: 66 83 c0 3c add ax,0x3c
400099: 48 31 ff xor rdi,rdi
40009c: 0f 05 syscall
000000000040009e <two>:
40009e: e8 df ff ff ff 48 00
.....H.
编码提取:还有很多其他方法可以做到这一点。
$ for i in `objdump -d pushpam_001 | grep "^ " | cut -f2`; do echo -n '\x'$i; done; echo
\xeb\x1c\x5f\x48\x31\xc0\x04\x55\x48\x31\xf6\x66\x81\xc6\xf3\x02\x0f\x05\x48\x31\xc0\x66\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xdf\xff\xff\xff\x48\x00\x.....H.
C shellcode.c - 部分
...
unsigned char code[] = \
"\xeb\x1c\x5f\x48\x31\xc0\x04\x55\x48\x31\xf6\x66\x81\xc6\xf3\x02\x0f\x05\x48\x31\xc0\x66\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xdf\xff\xff\xff\x48\x00";
...
决赛:
./shellcode
--wxrw---t 1 david david 0 Jan 31 12:25 H
如果 was the only problem, building your C test with gcc -fno-pie -no-pie
会起作用,因为那时 char sh[]
会在虚拟地址的低 32 位 space,所以将指针截断到 32 位的系统调用仍然会起作用.
运行 您的程序在 strace
下以查看它实际进行的系统调用。 (除了 strace
在 64 位代码中错误地解码 int 0x80
系统调用,解码就像您使用 64 位 syscall
ABI 一样。调用编号和 arg 寄存器不同。)但至少你可以看到系统调用 return 值(对于 32 位 creat
和截断的 64 位指针,它将是 -EFAULT
。)
您也可以 gdb
单步执行并检查系统调用 return 值。不过,让 strace
解码系统调用 inputs 真的很棒,所以我建议移植您的代码以使用 64 位 ABI,这样它就可以正常工作.
此外,它实际上能够利用 64 位进程,其中缓冲区溢出位于内存中低 32 位之外的地址。 (例如,像堆栈一样)。所以是的,你真的应该停止使用 int 0x80
或坚持使用 32 位代码。
您还依赖于在代码运行之前将寄存器置零,就像它们在进程启动时一样,但在从其他任何地方调用时却不是。
xor al,al
在 mov al,8
之前是完全没有意义的,因为异或归零 al
不会清除高位字节。写入 32 位寄存器会清除高 32 位,但不会写入 8 位或 16 位寄存器。如果是这样,在使用 mov
之前就不需要异或归零,它也是只写的。
如果你想在机器码中设置RAX=8而不带任何零字节,你可以
push 8
/ pop rax
(3 个字节)
xor eax,eax
/ mov al,8
(4 字节)
- 或者给定一个清零的
rcx
寄存器,lea eax, [rcx+8]
(3 个字节)
将 CX 设置为 0755
并不是那么简单,因为常量不适合 imm8。您的 16 位 mov
是一个不错的选择(或者,如果您先将 rcx
归零,就会是。
xor ecx,ecx
lea eax, [rcx+8] ; SYS_creat = 8 from unistd_32.h
mov cx, 0755 ; mode
int 0x80 ; invoke 32-bit ABI
xor ebx,ebx
lea eax, [rbx+1] ; SYS_exit = 1
int 0x80
BITS 64
section .text
global _start
_start:
jmp short two
one:
pop rbx
xor al,al
xor cx,cx
mov al,8
mov cx,0755
int 0x80
xor al,al
inc al
xor bl,bl
int 0x80
two:
call one
db 'H'`
这是我的汇编代码。 然后我使用了两个命令。 "nasm -f elf64 newdir.s -o newdir.o" 和 "ld newdir.o -o newdir".I 运行 ./newdir 并且工作正常但是当我提取操作代码并尝试使用以下 c 程序测试此 shellcode 时。它不工作(没有分段错误)。我已经使用 cmd gcc newdir -z execstack
进行了编译#include <stdio.h>
char sh[]="\xeb\x16\x5b\x30\xc0\x66\x31\xc9\xb0\x08\x66\xb9\xf3\x02\xcd\x80\x30\xc0\xfe\xc0\x30\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x48";
void main(int argc, char **argv)
{
int (*func)();
func = (int (*)()) sh;
(int)(*func)();
}
objdump -d newdir
newdir: file format elf64-x86-64
Disassembly of section .text:
0000000000400080 <_start>:
400080: eb 16 jmp 400098 <two>
0000000000400082 <one>:
400082: 5b pop %rbx
400083: 30 c0 xor %al,%al
400085: 66 31 c9 xor %cx,%cx
400088: b0 08 mov [=13=]x8,%al
40008a: 66 b9 f3 02 mov [=13=]x2f3,%cx
40008e: cd 80 int [=13=]x80
400090: 30 c0 xor %al,%al
400092: fe c0 inc %al
400094: 30 db xor %bl,%bl
400096: cd 80 int [=13=]x80
0000000000400098 <two>:
400098: e8 e5 ff ff ff callq 400082 <one>
40009d: 48 rex.W
当我 运行 ./a.out 时,我得到了照片中的东西。我附上照片是因为我无法解释发生了什么。image
P.S- 我的问题已经解决了。但我想知道哪里出了问题。所以我使用了调试器,结果如下 `
(gdb) list
1 char shellcode[] = "\xeb\x16\x5b\x30\xc0\x66\x31\xc9\xb0\x08\x66\xb9\xf3\x02\xcd\x80\x30\xc0\xfe\xc0\x30\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x48";
2 int main (int argc, char **argv)
3 {
4 int (*ret)();
5 ret = (int(*)())shellcode;
6
7 (int)(*ret)();
8 } (gdb) disassemble main
Dump of assembler code for function main:
0x00000000000005fa <+0>: push %rbp
0x00000000000005fb <+1>: mov %rsp,%rbp
0x00000000000005fe <+4>: sub [=14=]x20,%rsp
0x0000000000000602 <+8>: mov %edi,-0x14(%rbp)
0x0000000000000605 <+11>: mov %rsi,-0x20(%rbp)
0x0000000000000609 <+15>: lea 0x200a20(%rip),%rax # 0x201030 <shellcode>
0x0000000000000610 <+22>: mov %rax,-0x8(%rbp)
0x0000000000000614 <+26>: mov -0x8(%rbp),%rdx
0x0000000000000618 <+30>: mov [=14=]x0,%eax
0x000000000000061d <+35>: callq *%rdx
0x000000000000061f <+37>: mov [=14=]x0,%eax
0x0000000000000624 <+42>: leaveq
0x0000000000000625 <+43>: retq
End of assembler dump.
(gdb) b 7
Breakpoint 1 at 0x614: file test.c, line 7.
(gdb) run
Starting program: /root/Desktop/Progs/shell/a.out
Breakpoint 1, main (argc=1, argv=0x7fffffffe2b8) at test.c:7
7 (int)(*ret)();
(gdb) info registers rip
rip 0x555555554614 0x555555554614 <main+26>
(gdb) x/5i $rip
=> 0x555555554614 <main+26>: mov -0x8(%rbp),%rdx
0x555555554618 <main+30>: mov [=14=]x0,%eax
0x55555555461d <main+35>: callq *%rdx
0x55555555461f <main+37>: mov [=14=]x0,%eax
0x555555554624 <main+42>: leaveq
(gdb) s
(Control got stuck here, so i pressed ctrl+c)
^C
Program received signal SIGINT, Interrupt.
0x0000555555755048 in shellcode ()
(gdb) x/5i 0x0000555555755048
=> 0x555555755048 <shellcode+24>: callq 0x555555755032 <shellcode+2>
0x55555575504d <shellcode+29>: rex.W add %al,(%rax)
0x555555755050: add %al,(%rax)
0x555555755052: add %al,(%rax)
0x555555755054: add %al,(%rax)
这里是调试信息。我找不到控件的位置 wrong.If 需要更多信息请询问。
下面是一个使用 x86-64 的工作示例;可以进一步优化大小。最后一个 0x00 null 可以用于执行 shellcode。
assemble & link:
$ nasm -felf64 -g -F dwarf pushpam_001.s -o pushpam_001.o && ld pushpam_001.o -o pushpam_001
代码:
BITS 64
section .text
global _start
_start:
jmp short two
one:
pop rdi ; pathname
xor rax, rax
add al, 85 ; creat syscall 64-bit Linux
xor rsi, rsi
add si, 0755 ; mode - octal
syscall
xor rax, rax
add ax, 60
xor rdi, rdi
syscall
two:
call one
db 'H',0
objdump:
pushpam_001: file format elf64-x86-64
0000000000400080 <_start>:
400080: eb 1c jmp 40009e <two>
0000000000400082 <one>:
400082: 5f pop rdi
400083: 48 31 c0 xor rax,rax
400086: 04 55 add al,0x55
400088: 48 31 f6 xor rsi,rsi
40008b: 66 81 c6 f3 02 add si,0x2f3
400090: 0f 05 syscall
400092: 48 31 c0 xor rax,rax
400095: 66 83 c0 3c add ax,0x3c
400099: 48 31 ff xor rdi,rdi
40009c: 0f 05 syscall
000000000040009e <two>:
40009e: e8 df ff ff ff 48 00
.....H.
编码提取:还有很多其他方法可以做到这一点。
$ for i in `objdump -d pushpam_001 | grep "^ " | cut -f2`; do echo -n '\x'$i; done; echo
\xeb\x1c\x5f\x48\x31\xc0\x04\x55\x48\x31\xf6\x66\x81\xc6\xf3\x02\x0f\x05\x48\x31\xc0\x66\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xdf\xff\xff\xff\x48\x00\x.....H.
C shellcode.c - 部分
...
unsigned char code[] = \
"\xeb\x1c\x5f\x48\x31\xc0\x04\x55\x48\x31\xf6\x66\x81\xc6\xf3\x02\x0f\x05\x48\x31\xc0\x66\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xdf\xff\xff\xff\x48\x00";
...
决赛:
./shellcode
--wxrw---t 1 david david 0 Jan 31 12:25 H
如果 gcc -fno-pie -no-pie
会起作用,因为那时 char sh[]
会在虚拟地址的低 32 位 space,所以将指针截断到 32 位的系统调用仍然会起作用.
运行 您的程序在 strace
下以查看它实际进行的系统调用。 (除了 strace
在 64 位代码中错误地解码 int 0x80
系统调用,解码就像您使用 64 位 syscall
ABI 一样。调用编号和 arg 寄存器不同。)但至少你可以看到系统调用 return 值(对于 32 位 creat
和截断的 64 位指针,它将是 -EFAULT
。)
您也可以 gdb
单步执行并检查系统调用 return 值。不过,让 strace
解码系统调用 inputs 真的很棒,所以我建议移植您的代码以使用 64 位 ABI,这样它就可以正常工作.
此外,它实际上能够利用 64 位进程,其中缓冲区溢出位于内存中低 32 位之外的地址。 (例如,像堆栈一样)。所以是的,你真的应该停止使用 int 0x80
或坚持使用 32 位代码。
您还依赖于在代码运行之前将寄存器置零,就像它们在进程启动时一样,但在从其他任何地方调用时却不是。
xor al,al
在 mov al,8
之前是完全没有意义的,因为异或归零 al
不会清除高位字节。写入 32 位寄存器会清除高 32 位,但不会写入 8 位或 16 位寄存器。如果是这样,在使用 mov
之前就不需要异或归零,它也是只写的。
如果你想在机器码中设置RAX=8而不带任何零字节,你可以
push 8
/pop rax
(3 个字节)xor eax,eax
/mov al,8
(4 字节)- 或者给定一个清零的
rcx
寄存器,lea eax, [rcx+8]
(3 个字节)
将 CX 设置为 0755
并不是那么简单,因为常量不适合 imm8。您的 16 位 mov
是一个不错的选择(或者,如果您先将 rcx
归零,就会是。
xor ecx,ecx
lea eax, [rcx+8] ; SYS_creat = 8 from unistd_32.h
mov cx, 0755 ; mode
int 0x80 ; invoke 32-bit ABI
xor ebx,ebx
lea eax, [rbx+1] ; SYS_exit = 1
int 0x80