1. 程式人生 > >CTF 學習筆記 03--Linux運維

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

        #重啟SSH服務前建議多保留一個會話以防不測

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

*    ssh弱密碼爆破

##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實在不好刪的話(三種掛馬方式如果是環鏈的啟用關係),直接恢復備份。