前言
参考:
https://fushuling.com/index.php/2023/06/01/awd/
https://5ime.cn/awdp.html#nexmoe-content
https://hackerpoet.com/index.php/archives/988/
Waf
PHP
命令执行
function wafrce($str){
return !preg_match("/openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|scandir|assert|pcntl_exec|fwrite|curl|system|eval|assert|flag|passthru|exec|chroot|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore/i", $str);
}
if (preg_match('/passthru|system|tail|flag|exec|base64/i', $_SERVER['REQUEST_URI'])) {
die('no!');
}
sql注入
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);
}
$username = addslashes($username);
$password = addslashes($password);
XSS
function wafxss($str){
return !preg_match("/\'|http|\"|\`|cookie|<|>|script/i", $str);
}
目录穿越
$action = (isset($_GET['action']) ? $_GET['action'] : 'home.php');
$deny_ext = array("..","../");
if (in_array($action, $deny_ext)){
if (file_exists($action)) {
include $action;
} else {
echo "File not found!";
}
}
文件上传
<?php
$allowed_extensions = array("jpg", "png", "gif"); // 允许上传的文件后缀名
$filename = $_FILES["file"]["name"];
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); // 获取文件后缀名并转换为小写
if (!in_array($extension, $allowed_extensions)) { // 检查文件后缀名是否在允许上传的列表中
echo "不允许上传该类型的文件!";
} else {
$target_file = "uploads/" . basename($filename); // 为上传文件指定目标路径
move_uploaded_file($_FILES["file"]["tmp_name"], $target_file); // 将文件从临时目录移动到目标路径
echo "文件上传成功!";
}
}
Python
filter_list = ["apple", "banana", "cherry"]
strings = "ana" # 匹配包含"ana"的字符串
for i in filter_list:
if i in strings:
raise ValueError("Hacker!")
else:
...
Node
过滤后缀:如果依赖里有上传中间件
// 配置 multer 上传中间件
const upload = multer({
storage: storage, // 使用自定义存储选项
fileFilter: (req, file, cb) => {
const fileExt = path.extname(file.originalname).toLowerCase();
if (fileExt === '.ejs') {
// 如果文件后缀为 .ejs,则拒绝上传该文件
return cb(new Error('Upload of .ejs files is not allowed'), false);
}
if (fileExt === '.js') {
// 如果文件后缀为 .js,则拒绝上传该文件
return cb(new Error('Upload of .js files is not allowed'), false);
}
cb(null, true); // 允许上传其他类型的文件
}
});
过滤目录穿越的后缀:
if (newPath && /app\.js|\\|\.ejs|node_modules/i.test(newPath)) {
return res.status(400).send('Invalid file name');
}
if (oldPath && /\.\.|flag|node_modules/i.test(oldPath)) {
return res.status(400).send('Invalid file name');
}
过滤关键词:
function waf(query) {
if (query.includes("flag") || query.includes("nc")) {
throw new Error("禁止使用 flag 和 nc 关键字!");
} else {
// 执行正常操作
}
}
Java
检测解码后的payload是否含有恶意类
String sea = new String(decodemsg);
if(!sea.contains("com.sea.")){
return "filtered";
}
thymeleaf ssti
@Controller
public class AboutController {
@GetMapping({"/about"})
public String about(HttpSession session, @RequestParam(defaultValue = "") String type) {
String username = (String)session.getAttribute("name");
if (StringUtils.isEmpty(username))
return "about/tourist/about";
if (!type.equals(""))
return "about/" + type + "/about";
return "about/user/about";
}
}
fix版本:
@Controller
public class AboutController {
@GetMapping({"/about"})
public String about(HttpSession session, @RequestParam(defaultValue = "") String type) {
String username = (String)session.getAttribute("name");
if (StringUtils.isEmpty(username))
return "about/tourist/about";
if (!type.equals("")) {
if (type.equals("system"))
return "about/system/about";
if (type.equals("tourist"))
return "about/tourist/about";
if (type.equals("user"))
return "about/user/about";
return "index";
}
return "about/user/about";
}
}
任意方法调用
@Controller
public class LogOutController {
@GetMapping({"/logout"})
public String logout(HttpServletRequest request, HttpSession session, @RequestParam(defaultValue = "logout") String method, @RequestParam(defaultValue = "com.mengda.awd.Utils.SessionUtils") String targetclass) throws Exception {
Class<?> ObjectClass = Class.forName(targetclass);
Constructor<?> constructor = ObjectClass.getDeclaredConstructor(new Class[0]);
constructor.setAccessible(true);
Object CLassInstance = constructor.newInstance(new Object[0]);
try {
if (method.equals("logout")) {
Method targetMethod = ObjectClass.getMethod(method, new Class[] { HttpSession.class });
targetMethod.invoke(CLassInstance, new Object[] { session });
} else {
Method targetMethod = ObjectClass.getMethod(method, new Class[] { String.class });
targetMethod.invoke(CLassInstance, new Object[] { request.getHeader("X-Forwarded-For") });
}
} catch (Exception e) {
return "redirect:/";
}
return "redirect:/";
}
}
fix:
@Controller
public class LogOutController {
@GetMapping({"/logout"})
public String logout(HttpServletRequest request, HttpSession session, @RequestParam(defaultValue = "logout") String method, @RequestParam(defaultValue = "com.mengda.awd.Utils.SessionUtils") String targetclass) throws Exception {
String[] blackList = {
"cat", "flag", "exec", "tac", "/", "*", "sh", "bash", "Runtime", "ProcessBuilder",
"ProcessImpl", "UNIXProcess", "File", "Read", "run", "build", "start" };
for (String s : blackList) {
if ("X-Forwarded-For".contains(s))
return "index";
}
for (String s : blackList) {
if (targetclass.contains(s))
return "index";
}
for (String s : blackList) {
if (method.contains(s))
return "index";
}
Class<?> ObjectClass = Class.forName(targetclass);
Constructor<?> constructor = ObjectClass.getDeclaredConstructor(new Class[0]);
constructor.setAccessible(true);
Object CLassInstance = constructor.newInstance(new Object[0]);
try {
if (method.equals("logout")) {
Method targetMethod = ObjectClass.getMethod(method, new Class[] { HttpSession.class });
targetMethod.invoke(CLassInstance, new Object[] { session });
} else {
Method targetMethod2 = ObjectClass.getMethod(method, new Class[] { String.class });
targetMethod2.invoke(CLassInstance, new Object[] { request.getHeader("X-Forwarded-For") });
}
return "redirect:/";
} catch (Exception e) {
return "redirect:/";
}
}
}
任意文件读取
@WebFilter(urlPatterns = {"/*"})
public class myFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
super.init(filterConfig);
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
String request_uri = URLDecoder.decode(request.getRequestURI(), "utf-8");
if (Check.check(request_uri).booleanValue()) {
String static_resources_path = "/usr/local/tomcat/webapps/app/WEB-INF/classes/static/" + request_uri;
static_resources_path = URLDecoder.decode(static_resources_path, "utf-8");
try {
servletResponse.getWriter().write(File.readFile(static_resources_path));
} catch (Exception e) {
servletResponse.getWriter().write("error~");
}
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
public void destroy() {
super.destroy();
}
}
fix:直接对File类下手
public class File {
public static String readFile(String filePath) throws Exception {
String[] blackList = { "flag", ".." };
for (String s : blackList) {
if (filePath.contains(s))
return "hacker";
}
String file_content = "";
FileInputStream fileInputStream = null;
try {
try {
fileInputStream = new FileInputStream(filePath);
byte[] bytes = new byte[4];
while (true) {
int readCount = fileInputStream.read(bytes);
if (readCount == -1)
break;
file_content = file_content + new String(bytes, 0, readCount);
}
fileInputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
fileInputStream.close();
}
return file_content;
} catch (Throwable th) {
fileInputStream.close();
throw th;
}
}
}
重写resolveClass
在将字节码恢复为类的过程中,调用了resolveClass
方法,而这个resolveClass方法如果被重写的话,调用的就是重写类的resolvceClass
我们如果在重写的resolvceClass中写入代码,即可控制需要恢复类的名称
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
Iterator var2 = BLACKLIST.iterator();
String s;
do {
if (!var2.hasNext()) {
return super.resolveClass(desc);
}
s = (String)var2.next();
} while(!desc.getName().startsWith(s));
throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName());
}
static {
BLACKLIST.add("com.sun.jndi");
BLACKLIST.add("com.fasterxml.jackson");
BLACKLIST.add("org.springframework");
BLACKLIST.add("com.sun.rowset.JdbcRowSetImpl");
BLACKLIST.add("java.security.SignedObject");
BLACKLIST.add("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
BLACKLIST.add("java.lang.Runtime");
BLACKLIST.add("java.lang.ProcessBuilder");
BLACKLIST.add("java.util.PriorityQueue");
}
Golang
package main
import (
"fmt"
"strings"
)
func main() {
filterList := []string{"apple", "banana", "cherry"}
str := "ana" // 匹配包含"ana"的字符串
for _, s := range filterList {
if strings.Contains(s, str) {
panic("Hacker!")
}
}
}
Update
update.sh
常规php文件:
cp 要替换的文件 /var/www/html/待替换的文件
python:
#!/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:
#!/bin/sh
cp server.js /app/server.js
ps -ef | grep node | grep -v grep | awk '{print $2}' | xargs kill -9
cd /app && nohup node server.js >> /opt/aa.log 2>&1 &
golang:
cp ./修改后编译好的文件 /编译文件的目录
ps -ef |grep go编译的名字| awk '{print $2}' | xargs kill -9
cd /编译文件目录 &&./执行编译文件 > /dev/null 2>&1
java:
直接覆盖jar包重启环境