封闭系统 shellcode 实验(segfault)
Closed system shellcode experimentation (segfault)
我正在参加在线软件安全课程。我正在尝试使用 shell 代码进行试验。我已经编写了一个易受攻击的服务器、一个注入程序、一个(可能损坏的)shell代码,我将其转换为程序集,然后用 python 脚本剥离。然后,我使用 shell 脚本编译并 运行 所有内容。我包括了我所有的文件,尽管我很确定我没有正确制作 shellcode
二进制文件。
vulnerable.c
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
int main(void) {
int sd, sdc, addrsize, ret, i;
struct sockaddr_in addr;
char exec[1024], buf[128];
void (*fn)(void);
const short family = AF_INET;
fn = (void (*)(void))exec;
addrsize = sizeof(struct sockaddr_in);
sd = socket(family, SOCK_STREAM, IPPROTO_TCP);
if (sd < 0) {
perror("socket");
return 1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(8000);
if (bind(sd, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
perror("bind");
return 2;
}
listen(sd, 1);
sdc = accept(sd, (struct sockaddr *)&addr, &addrsize);
i = 0;
do {
i += ret = read(sdc, buf, 128);
memcpy(exec + i, buf, ret);
} while (ret > 0);
close(sd);
fn();
return 0;
}
inject.c
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int sd, fd, ret, buflen = 128;
struct sockaddr_in addr;
FILE *f;
const char fname[] = "shellcode";
char buf[buflen];
const short family = AF_INET;
const char host[] = "127.0.0.1";
f = fopen(fname, "r");
fd = fileno(f);
sd = socket(family, SOCK_STREAM, IPPROTO_TCP);
if (sd < 0) {
perror("socket");
return 1;
}
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = family;
addr.sin_port = htons(8000);
inet_pton(family, host, &(addr.sin_addr.s_addr));
ret = connect(sd, (struct sockaddr*)&addr, sizeof(struct sockaddr));
if (ret < 0) {
perror("connect");
return 2;
}
do {
ret = read(fd, buf, buflen);
if (write(sd, buf, ret) != ret)
perror("write");
} while (ret > 0);
close(fd);
close(sd);
return 0;
}
shellcode.c
void shellcode(void) {
char sz[6] = { 'h', 'e', 'l', 'l', 'o', '[=12=]' };
write(1, sz, 6);
}
stripshellcode.py
copy = False
outf = open("shellcode-stripped.s", "w")
for line in open("shellcode.s").read().split("\n"):
if copy:
outf.write(line + "\n")
if "shellcode:" in line:
copy = True
elif "ret" in line and copy:
copy = False
outf.close()
make.sh
gcc -S shellcode.c && \
python stripshellcode.py && \
gcc -c shellcode-stripped.s -o shellcode && \
gcc inject.c -o inject && \
gcc vulnerable.c -o vulnerable && \
./vulnerable & ./inject
输出
$ sh make.sh
make.sh: line 6: 13905 Segmentation fault ./vulnerable
我这个实验过程哪里出错了?
编辑:
我应该注意 "closed system" 我的意思是这是在虚拟机中执行的(检查绑定地址),这也意味着一些变量为了简洁而以依赖的方式硬编码轻松.
据我了解,您正在尝试使用缓冲区溢出来注入 shell 脚本。编译器在缓冲区周围添加保护,以防止您尝试执行的操作。您应该在编译易受攻击的应用程序时禁用它们。
我做了一个类似的实验,我使用了这个选项:
badbuf: vulnerable.c
$(CC) -g -Wall -fno-stack-protector -o badbuf vulnerable.c
这不起作用,因为 shellcode 文件是一个目标文件。它是一种供链接器使用的中间文件格式。将其视为一系列指令是完全错误的。目标文件包含代码等。然而这段代码是不完整的。当代码引用符号时,如写入,将插入占位符而不是地址。链接器的工作是将多个目标文件和库拼接在一起,在内存中布局代码,有效地将地址分配给符号,最后修补占位符。
即使生成了可执行文件,它仍然无法运行,因为现代可执行格式需要加载程序才能 运行。基本上,加载程序读取存储在可执行文件中的元数据,将文件中的多个部分映射到内存中,进行调整,最后将控制权转移到由元数据定义的入口点。
我认为制作 shellcode 有几种可行的方法。
手动编码汇编序列。
用工具帮你编码
研究目标文件格式并提取代码,我想 objdump 可以为您完成。
要求链接器以不需要加载程序的格式生成可执行文件 运行。
阅读其他答案我意识到故障实际上发生得更早 - exec 缓冲区分配在堆栈上,堆栈内存保护属性明确拒绝执行。可以使用 Linux.
上的 say execstack 实用程序关闭此保护
我正在参加在线软件安全课程。我正在尝试使用 shell 代码进行试验。我已经编写了一个易受攻击的服务器、一个注入程序、一个(可能损坏的)shell代码,我将其转换为程序集,然后用 python 脚本剥离。然后,我使用 shell 脚本编译并 运行 所有内容。我包括了我所有的文件,尽管我很确定我没有正确制作 shellcode
二进制文件。
vulnerable.c
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
int main(void) {
int sd, sdc, addrsize, ret, i;
struct sockaddr_in addr;
char exec[1024], buf[128];
void (*fn)(void);
const short family = AF_INET;
fn = (void (*)(void))exec;
addrsize = sizeof(struct sockaddr_in);
sd = socket(family, SOCK_STREAM, IPPROTO_TCP);
if (sd < 0) {
perror("socket");
return 1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(8000);
if (bind(sd, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
perror("bind");
return 2;
}
listen(sd, 1);
sdc = accept(sd, (struct sockaddr *)&addr, &addrsize);
i = 0;
do {
i += ret = read(sdc, buf, 128);
memcpy(exec + i, buf, ret);
} while (ret > 0);
close(sd);
fn();
return 0;
}
inject.c
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int sd, fd, ret, buflen = 128;
struct sockaddr_in addr;
FILE *f;
const char fname[] = "shellcode";
char buf[buflen];
const short family = AF_INET;
const char host[] = "127.0.0.1";
f = fopen(fname, "r");
fd = fileno(f);
sd = socket(family, SOCK_STREAM, IPPROTO_TCP);
if (sd < 0) {
perror("socket");
return 1;
}
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = family;
addr.sin_port = htons(8000);
inet_pton(family, host, &(addr.sin_addr.s_addr));
ret = connect(sd, (struct sockaddr*)&addr, sizeof(struct sockaddr));
if (ret < 0) {
perror("connect");
return 2;
}
do {
ret = read(fd, buf, buflen);
if (write(sd, buf, ret) != ret)
perror("write");
} while (ret > 0);
close(fd);
close(sd);
return 0;
}
shellcode.c
void shellcode(void) {
char sz[6] = { 'h', 'e', 'l', 'l', 'o', '[=12=]' };
write(1, sz, 6);
}
stripshellcode.py
copy = False
outf = open("shellcode-stripped.s", "w")
for line in open("shellcode.s").read().split("\n"):
if copy:
outf.write(line + "\n")
if "shellcode:" in line:
copy = True
elif "ret" in line and copy:
copy = False
outf.close()
make.sh
gcc -S shellcode.c && \
python stripshellcode.py && \
gcc -c shellcode-stripped.s -o shellcode && \
gcc inject.c -o inject && \
gcc vulnerable.c -o vulnerable && \
./vulnerable & ./inject
输出
$ sh make.sh
make.sh: line 6: 13905 Segmentation fault ./vulnerable
我这个实验过程哪里出错了?
编辑:
我应该注意 "closed system" 我的意思是这是在虚拟机中执行的(检查绑定地址),这也意味着一些变量为了简洁而以依赖的方式硬编码轻松.
据我了解,您正在尝试使用缓冲区溢出来注入 shell 脚本。编译器在缓冲区周围添加保护,以防止您尝试执行的操作。您应该在编译易受攻击的应用程序时禁用它们。
我做了一个类似的实验,我使用了这个选项:
badbuf: vulnerable.c
$(CC) -g -Wall -fno-stack-protector -o badbuf vulnerable.c
这不起作用,因为 shellcode 文件是一个目标文件。它是一种供链接器使用的中间文件格式。将其视为一系列指令是完全错误的。目标文件包含代码等。然而这段代码是不完整的。当代码引用符号时,如写入,将插入占位符而不是地址。链接器的工作是将多个目标文件和库拼接在一起,在内存中布局代码,有效地将地址分配给符号,最后修补占位符。
即使生成了可执行文件,它仍然无法运行,因为现代可执行格式需要加载程序才能 运行。基本上,加载程序读取存储在可执行文件中的元数据,将文件中的多个部分映射到内存中,进行调整,最后将控制权转移到由元数据定义的入口点。
我认为制作 shellcode 有几种可行的方法。
手动编码汇编序列。
用工具帮你编码
研究目标文件格式并提取代码,我想 objdump 可以为您完成。
要求链接器以不需要加载程序的格式生成可执行文件 运行。
阅读其他答案我意识到故障实际上发生得更早 - exec 缓冲区分配在堆栈上,堆栈内存保护属性明确拒绝执行。可以使用 Linux.
上的 say execstack 实用程序关闭此保护