备战6月23日的CISCN线下赛 AWDP
前言 本次CISCN华东南赛区我们学校是承办方,当然晋级名额变成三队,不过由于本人实力有限加上最后黑灯的时候差一点做出来easycms-revenge
,本来都打算退役了。在看到主办方发的晋级名单后,发现我们以倒一晋级线下赛,实在是续了下香火。既然都进了,总不能玩几小时pvz吧,所以打算从今天开始备战AWDP
AWDP 首先了解一下什么是 AWDP ,AWDP模式(Attack,Defense,WebandPwn),分为 Break 与 Fix 环节。根据英文全称也可以看出来,只有 Web 和 Pwn 这两个方向的题目。
每个战队拥有相同的起始分数及相同配置的虚拟靶机,参赛队员需对平台中的GameBox发起攻击,向平台提交正确的flag(证明自己具备对该题的攻击能力);在此期间,由平台以轮次制的方式向参赛战队的靶机发起攻击,检查其他选手的漏洞是否修补成功,若修补成功则认为参赛战队具备该漏洞的防御能力。
简单来说,AWDP 和传统 CTF 并无任何区别,仅仅是多了一个 Fix 功能,也就是你提交 flag 后拿到的是攻击分,而 Fix 成功后才会拿到防御分。
文件传输 这里以xshell和xftp为例
我们先使用xshell连接服务器,进入到test文件夹
然后新建一个shell,点击新建文件传输
然后自动弹出来xftp,添加会话连接
连接好后,右键对应文件点击传输即可
防守WAF 参考文章
PHP RCE 1 2 3 function wafrce($str){ return !preg_match("/openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|scandir|assert|pcntl_exec|fwrite|curl|system|eval|assert|tail|flag|exec|base64|passthru|exec|chroot|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore/i", $str); }
1 2 3 4 if (preg_match('/(system|exec|shell_exec|passthru|eval|assert)/i', $_GET['do'])) { die('hacker'); } return $_GET['do'];
SQL注入 1 2 3 function wafsqli($str){ return !preg_match("/select|and|\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\x26|\x7c|or|into|from|where|join|sleexml|extractvalue|+|regex|copy|read|file|create|grand|dir|insert|link|server|drop|=|>|<|;|\"|\'|\^|\|/i", $str); }
XSS 1 2 3 function wafxss($str){ return !preg_match("/\'|http|\"|\`|cookie|<|>|script/i", $str); }
文件上传 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 <?php // 允许上传的文件类型 $allowedExtensions = array("jpg", "jpeg", "png", "gif"); // 上传文件的目录 $uploadDir = "uploads/"; // 检查文件是否上传成功 if (isset($_FILES["file"])) { $file = $_FILES["file"]; // 获取文件的扩展名 $extension = pathinfo($file["name"], PATHINFO_EXTENSION); // 检查文件类型是否允许上传 if (!in_array(strtolower($extension), $allowedExtensions)) { echo "只允许上传以下类型的文件: " . implode(", ", $allowedExtensions); exit; } // 检查上传文件是否为真实的图像文件 if (getimagesize($file["tmp_name"]) === false) { echo "上传文件不是有效的图像文件。"; exit; } // 生成一个唯一的文件名以避免重复 $uniqueFileName = uniqid() . "." . $extension; // 移动上传的文件到目标目录 if (move_uploaded_file($file["tmp_name"], $uploadDir . $uniqueFileName)) { echo "文件上传成功!"; } else { echo "文件上传失败。"; } }
XXE 1 2 3 4 5 <?php $xmlData = file_get_contents('php://input'); libxml_disable_entity_loader(true); $xml = simplexml_load_string($xmlData); echo $xml->name;
Python 自定义过滤关键词
1 2 3 4 5 filter_list = ["apple", "banana", "cherry"] strings = "ana" # 匹配包含"ana"的字符串 for i in filter_list: if i in strings: print("Hacker!" )
Nodejs 自定义过滤关键词
1 2 3 4 5 6 7 const keywords = ["apple", "banana", "cherry"]; for (const i of keywords) { if (code.includes(i)) { console.log("Hacker!") } }
Java 自定义过滤关键词 1 2 3 4 5 6 7 8 String[] filterList = {"apple", "banana", "cherry"}; String str = "ana"; // 匹配包含"ana"的字符串 for (String s : filterList) { if (s.contains(str)) { System.out.println("Hacker!"); } }
SSRF 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 /** @ author: Drunkbaby @ usages: 用于 SSRF 的自定义防护 去到对应的接口下面修改即可 */ 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; /** @ author: Drunkbaby @ usages: 用于 SSRF 的自定义防护 @ ban 了几个协议,如果单纯全部阻挡什么 127.0.0.1,业务不一定过得去。 */ @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 = "file|http|jar|gopher|tar|war"; String[] badStrs = badStr.split("\\|"); for (int i = 0; i < badStrs.length; i++) { //循环检测,判断在请求参数当中是否包含SQL关键字 if (str.indexOf(badStrs[i]) >= 0) { return true; } } return false; } }
log4j2 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 package com.ruoyi.common.xss; 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; /** @ author: Drunkbaby @ usages: 用于 log4j2 的自定义防护 @ 过滤 url:在 WebFilter 当中添加 urlPatterns */ @Component @WebFilter(urlPatterns = "/system/role/list", filterName = "sqlInjectFilter") public class Log4j2Filter 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 = "$|$$|jndi|rmi|ldap|{|}|"; String[] badStrs = badStr.split("\\|"); for (int i = 0; i < badStrs.length; i++) { //循环检测,判断在请求参数当中是否包含log4j2关键字 if (str.indexOf(badStrs[i]) >= 0) { return true; } } return false; } }
文件上传 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 /** @ author: Drunkbaby @ usages: 用于文件上传的接口修改 @ 需要在对应接口中修改 */ @RestController public class securityUpload { @RequestMapping("/securityUpload") public String handleFileUpload(@RequestParam("file") MultipartFile file){ if (file.isEmpty()){ return "请上传文件"; } // 获取文件名 String fileName = file.getOriginalFilename(); String suffix = fileName.substring(fileName.lastIndexOf(".")); String contentType = file.getContentType(); //过滤 String[] picWhite = {".png",".jpg",".gif",".webp",".bmp"}; String[] white_type = {"image/gif","image/jpeg","image/jpg","image/png"}; Boolean SuffixFlag = false; Boolean TypeFlag = false; for (String pic_suffix:picWhite){ if (suffix.toLowerCase().equals(pic_suffix)){ SuffixFlag = true; break; } } for (String white_suffix:white_type){ if (contentType.toLowerCase().equals(white_suffix)){ TypeFlag = true; break; } } if (!SuffixFlag||!TypeFlag){ return "File Type not allow"; } String filePath = System.getProperty("user.dir")+"/tmp"; Date date = new Date(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss"); String newfileName = dateFormat.format(date)+Integer.toHexString((int)new Date().getTime())+suffix; File dest = new File(filePath+File.separator+newfileName); if (!dest.getParentFile().exists()){ dest.getParentFile().mkdirs(); } try{ file.transferTo(dest); return "上传成功"; } catch (IOException e) { e.printStackTrace(); return "上传失败"; } } }
fastjson 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 package FastjsonFilters; import java.util.Objects; import java.util.regex.Pattern; /** @ author: Drunkbaby @ usages: 用于 Fastjson 的自定义防护 @ 针对 1.2.24 版本,则只添加过滤即可,若针对其他版本 ParserConfig.getGlobalInstance().setAutoTypeSupport(false); 将 autoTypeSupprt 设置为 false */ public class Fastjson1224Filter { public String Unserjson(@RequestParam String str, @RequestParam String input) throws Exception { if (str != null && Objects.hashCode(str) == secret.getKey().hashCode() && !secret.getKey().equals(str)) { String pattern = ".*rmi.*|.*jndi.*|.*ldap.*|.*\\\\x.*"; Pattern p = Pattern.compile(pattern, 2); boolean StrMatch = p.matcher(input).matches(); if (StrMatch) { return "Hacker get out!!!"; } ParserConfig.getGlobalInstance().setAutoTypeSupport(true); JSON.parseObject(input); } return "hello"; } }
Golang 自定义过滤关键词
1 2 3 4 5 6 7 filterList := []string{"apple", "banana", "cherry"} str := "ana" // 匹配包含"ana"的字符串 for _, s := range filterList { if strings.Contains(s, str) { fmt.Println("Hacker!") } }
防御修复 打包&解包 1 tar -zcvf update.tar.gz update.sh file1 file2
如果要求把要修补的文件上传到服务器里,替换原来服务器中的文件,所以我们要知道文件具体的路径,大概思路就是在根目录下查找该漏洞对应的文件路径,然后把我们修复的上传即可
PHP php不用重启服务,我们先cp把源码保存下来
1 cp index.php ../index.php
然后把改好的文件移到对应位置
1 mv -f explorer.php index/explorer.php
python 1 2 3 4 #!/bin/sh cp app.py /app/app.py ps -ef | grep python | grep -v grep | awk '{print $2}' | xargs kill -9 cd /app && nohup python app.py >> /opt/app.log 2>&1 &
nodejs 1 2 3 4 #!/bin/sh cp ./app.js /app/app.js ps -ef | grep app.js | grep -v grep | awk '{print $2}' | xargs kill -9 nohup node /app/app.js || tail -f /dev/null &
参考文章 https://5ime.cn/awdp.html
https://blog.csdn.net/weixin_51614272/article/details/125527593
https://fushuling.com/index.php/2024/06/15/ciscn%e8%a5%bf%e5%8d%97%e5%a4%8d%e8%b5%9bawdp-web/