CTF 学习笔记 03--Linux运维

注:linux上很少出现远程溢出漏洞,攻进linux一般拷爆破或通过控制Windows监视Linux行为进入(键盘记录器)

##运维流程-SSH

*    密钥登录

        

        #禁止密码登录并配置公私钥登录

#编辑sshd_config文件
vi /etc/ssh/sshd_config
#禁用密码验证
PasswordAuthentication no
#启用密钥验证
RSAAuthentication yes
PubkeyAuthentication yes
#指定公钥数据库文件
AuthorsizedKeysFile .ssh/authorized_keys
         #或者直接输入下面的命令
sed -i "s/^PasswordAuthentication.*/PasswordAuthentication no/g" /etc/ssh/sshd_config
sed -i "s/^#RSAAuthentication.*/RSAAuthentication yes/g" /etc/ssh/sshd_config
sed -i "s/^#PubkeyAuthentication.*/PubkeyAuthentication yes/g" /etc/ssh/sshd_config
sed -i "s/^#AuthorizedKeysFile.*/AuthorizedKeysFile .ssh\/authorized_keys/g" /etc/ssh/sshd_config

        #配置SSHD公钥登陆 
https://blog.csdn.net/mchdba/article/details/52193812

        #重启SSH服务前建议多保留一个会话以防不测

#RHEL/CentOS系统
service sshd restart
#ubuntu系统
service ssh restart
#debian系统
/etc/init.d/ssh restart

*    ssh弱密码爆破

nmap 扫描 22
hydra  -user   -p 
crunch    字典生成工具
https://blog.csdn.net/qq_33936481/article/details/51277679   

##web源码备份

  远程获取文件
            scp -r Web1:/var/www/html/ webbak/

          备份最好基于时间备份,每隔一个小时备份一次,最好保留原始备份。

#!/bin/bash
time=`/bin/date +%F`
bak_file="/data/backup/$time.tar.gz"
webdir="/data/www/"
tar zcvf $bak_file $webdir >/dev/null 2>&1 &
计划任务 
    crontable -e
  30 * * * * /bin/bash /data/bak.sh    #添加定时执行任务
        ctl+o        #保存        ctl+x        #退出
##数据库备份
mysqldump -uroot -p --single-transaction --all-databases > backup.sql # 所有

mysqldump -u root -p --single-transaction dataname > dataname.sql     #单个

mysqldump --skip-lock-tables -uxxxx -pxxxxxx -h 166.111.9.173 -R 数据库名 > ./urlevent20180319.sql 

mysqldump -h127.0.0.1 -uroot -ppassword database |gzip >$backupDir/$database-$today.sql.gz`然后,scp回来。
shell脚本原理:
#备份目录
backupDir=/home/backup/database
#mysqlDump
mysqldump=/usr/local/mariadb/bin/mysqldump
host=127.0.0.1
username=root
password=42342342
today=`date +%Y%m%d`
#要备份的数据库数组
databases=(blog chinese_medicine)
# echo $databaseCount
for database in ${databases[@]}
  do
    echo '开始备份'$database
    $mysqldump -h$host -u$username -p$password $database | gzip > $backupDir/$database-$today.sql.gz
    echo '成功备份'$database'到'$backupDir/$database-$today.sql.gz
  done
恢复mysql
mysql -uroot -p TEST < bak.sql

##数据库运维

  取消远程登录(不需要远程管理

取消mysql密码认证:
修改my.cnf ,添加 skip-grant-tables

修改mysql密码
update mysql.user set password=PASSWORD('skyboy') where user='root' and host='localhost';
flush privileges;

最好先修改mysql,再修改php。一般不存在需要修改mysql密码的情况。

禁止数据库的远程连接:
use mysql;
update user set host='localhost' where user='root';
flush privileges;

数据库降权

CREATE USER ‘dog’@‘localhost’ IDENTIFIED BY ‘123456’;
GRANT ALL ON databasename.* TO ‘dog’@‘localhost
flush privileges;
调整站点配置文件,修改数据库连接的用户名和密码。通过本机或ssh登录。

##权限配置--Linux的精髓

对于非必须可写的目录:
权限设置为755,拥有者设为非www-data用户;从而防止文件被篡改/删除。 

对于必须可写的目录:

根据服务器类型,上一个.htaccess, 或者修改nginx的目录配置文件,去除此路径的脚本执行权限。

对于apache:

    <FileMatch ".(pjp|php3|php4|php5)|phtml)">
    Order Allow.Deny
    Deny from all
    <FilesMaych>    #禁止恶意脚本的上传

对于Nginx:修改配置文件

location ~ /mm/(data|uploads|templets)/*.(php)$ {
deny all;
}
location ~ .php$ {
try_files $uri /404.html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
} 
修改完成之后,nginx -S reload

##防御脚本

*    waf脚本   WAF需要同时具备拦截和抓取流量的作用。 

php-WAF的批量添加:

find /var/www/html -type f -path "*.php" | xargs sed -i "s/<?php/<?php require_once('/tmp/waf.php');n/g“
port-forwarding.py
import socket
import threading
import sys

def handle(buffer):
    return buffer

def transfer(src, dst, direction):
    src_name = src.getsockname()
    src_address = src_name[0]
    src_port = src_name[1]
    dst_name = dst.getsockname()
    dst_address = dst_name[0]
    dst_port = dst_name[1]
    while True:
        buffer = src.recv(0x400)
        if len(buffer) == 0:
            print "[-] No data received! Breaking..."
            break
        # print "[+] %s:%d => %s:%d [%s]" % (src_address, src_port, dst_address, dst_port, repr(buffer))
        if direction:
            print "[+] %s:%d >>> %s:%d [%d]" % (src_address, src_port, dst_address, dst_port, len(buffer))
        else:
            print "[+] %s:%d <<< %s:%d [%d]" % (dst_address, dst_port, src_address, src_port, len(buffer))
        dst.send(handle(buffer))
    print "[+] Closing connecions! [%s:%d]" % (src_address, src_port)
    src.shutdown(socket.SHUT_RDWR)
    src.close()
    print "[+] Closing connecions! [%s:%d]" % (dst_address, dst_port)
    dst.shutdown(socket.SHUT_RDWR)
    dst.close()

def server(local_host, local_port, remote_host, remote_port, max_connection):
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind((local_host, local_port))
    server_socket.listen(max_connection)
    print '[+] Server started [%s:%d]' % (local_host, local_port)
    print '[+] Connect to [%s:%d] to get the content of [%s:%d]' % (local_host, local_port, remote_host, remote_port)
    while True:
        local_socket, local_address = server_socket.accept()
        print '[+] Detect connection from [%s:%s]' % (local_address[0], local_address[1])
        print "[+] Trying to connect the REMOTE server [%s:%d]" % (remote_host, remote_port)
        remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        remote_socket.connect((remote_host, remote_port))
        print "[+] Tunnel connected! Tranfering data..."
        # threads = []
        s = threading.Thread(target=transfer, args=(
            remote_socket, local_socket, False))
        r = threading.Thread(target=transfer, args=(
            local_socket, remote_socket, True))
        # threads.append(s)
        # threads.append(r)
        s.start()
        r.start()
    print "[+] Releasing resources..."
    remote_socket.shutdown(socket.SHUT_RDWR)
    remote_socket.close()
    local_socket.shutdown(socket.SHUT_RDWR)
    local_socket.close()
    print "[+] Closing server..."
    server_socket.shutdown(socket.SHUT_RDWR)
    server_socket.close()
    print "[+] Server shuted down!"

def main():
    if len(sys.argv) != 5:
        print "Usage : "
        print "\tpython %s [L_HOST] [L_PORT] [R_HOST] [R_PORT]" % (sys.argv[0])
        print "Example : "
        print "\tpython %s 127.0.0.1 8888 127.0.0.1 22" % (sys.argv[0])
        exit(1)
    LOCAL_HOST = sys.argv[1]
    LOCAL_PORT = int(sys.argv[2])
    REMOTE_HOST = sys.argv[3]
    REMOTE_PORT = int(sys.argv[4])
    MAX_CONNECTION = 0x10
    server(LOCAL_HOST, LOCAL_PORT, REMOTE_HOST, REMOTE_PORT, MAX_CONNECTION)

if __name__ == "__main__":
    main()

*    监控脚本

#!/usr/bin/env python
# encoding:utf-8

import sys
import pyinotify
import os
import time

def detect_waf(pathname):
    try:
        with open(pathname) as f:
            content = f.read()
            black_list = ["<?", "<%"]
            black_list += ['eval', 'assert']
            black_list += ['passthru', 'exec', 'system', 'shell_exec', 'popen', 'proc_open']
            black_list += ['hightlight_file', 'show_source', 'php_strip_whitespace', 'file_get_contents', 'readfile', 'file', 'fopen', 'fread', 'include', 'include_once', 'require', 'require_once', 'fread', 'fgets', 'fpassthru', 'fgetcsv', 'fgetss', 'fscanf', 'parse_ini_file']
            black_list += ['glob', 'opendir', 'dir', 'readdir', 'scandir']
            FLAG = False
            for black in black_list:
                if black in content:
                    print "[!] Dangerous php script! (%s)" % (black)
                    print "[*] Content : "
                    print content.rstrip("\n")
                    FLAG = True
                    break
            if FLAG:
                target_path = "webshells/%s.log" % (time.strftime('%Y-%m-%d-%H:%M:%S',time.localtime(time.time())))
                print "[+] Detect webshell , moving from %s to %s" % (pathname, target_path)
                os.rename(pathname, target_path)
    except Exception as e:
        print "[-] %s" % (str(e))

class EventHandler(pyinotify.ProcessEvent):
    def process_IN_CREATE(self, event):
        if event.dir:
            print "Create Directory : %s" % (event.pathname)
        else:
            print "Create File : %s" % (event.pathname)

    def process_IN_DELETE(self, event):
        if event.dir:
            print "Delete Directory : %s" % (event.pathname)
        else:
            print "Delete File : %s" % (event.pathname)

    def process_IN_CLOSE_WRITE(self, event):
        if event.dir:
            print "Close Writable Directory : %s" % (event.pathname)
        else:
            print "Close Writable File : %s" % (event.pathname)
            detect_waf(event.pathname)

def main():
    if len(sys.argv) != 2:
        print "Usage : "
        print "\tpython %s [PATH]" % (sys.argv[0])
        exit(1)
    path = sys.argv[1]
    wm = pyinotify.WatchManager()
    wm.add_watch(path, pyinotify.ALL_EVENTS, rec=True)
    eh = EventHandler()
    notifier = pyinotify.Notifier(wm, eh)
    notifier.loop()

if __name__ == "__main__":
    main()

*    一句话木马  用以后期运维 具有web的权限以便于web操作(运维人员的权限往往不是web权限)

<?php
$serverList = array(
    "127.0.0.1",
    "::1"
);
$ip = $_SERVER['REMOTE_ADDR'];

foreach ($serverList as $host){
    if( $ip===$host){
		$a = $_POST['n985de9'];
		if(isset($a)) {
    		eval(base64_decode($a));
		}
    }else{
        die();
    }
}

## 查看网络拓扑 查看别人的防御机制 通过跳板机接入内网

masscan(一般用这个就好):
masscan -p 80 172.16.0.0/24
masscan -p0-65535 172.16.0.0/24 -oJ result.json

Nmap:
nmap -sn -T4 ip/24
nmap -Pn ip/24

##木马查杀

运维选手需要随时:

* 关注服务的可用性状况
* 查看文件监控情况
* 在被攻击的时候进行响应,保存相应的流量,查找/清除后门;


查看木马流程:

需要用www-data 权限进行查询  (web权限,如apache;具体可以通过上面一句话木马实现)
         crontab -l                        #查看计划任务
         ps aux|grep www-data   #查看以www-data权限运行的可疑流程

清除计划任务:
        crontab -r
        crontab -r -u USERNAME
杀死内存马:
        ps aux|grep www-data|awk '{print $2}'|xargs kill -9
杀死文件马: 通过文件监控脚本或流量监视定位木马
需要以www-data权限
        rm -rf 

webshell实在不好删的话(三种挂马方式如果是环链的激活关系),直接恢复备份。



猜你喜欢

转载自blog.csdn.net/qq_38055050/article/details/80720231