0%

awdp-web-小白

awdp

因为本章纯新手向,所以只讲讲防御应该怎么防御
awdp介绍
一般会给你一个附件让修复里面的漏洞,然后提交修复好的附件进行check,并且提交次数是有限制的,假如是5次,你提交5次都没check过,那你就不允许继续提交了,所以要谨慎修复

php

seay & d盾

下载后直接扫描,会给出漏洞结果,但是该工具是基于正则表达式,所以可能存在很多误报
d盾也可以扫描,但是扫描结果不全,但是准确率高点,推荐先用d盾进行扫描

seay无法扫描到一些较新的漏洞函数,还有反序列化的函数也无法扫描

watchbird

https://github.com/leohearts/awd-watchbird
根据教程直接安装

常见漏洞代码

下面只是给出漏洞代码,如果watchbird不能解决的问题,那也不是给小白解决的,所以只给出简单漏洞代码,和修复建议

sql

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
<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "test";

// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);

// 检查连接
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}

if (isset($_POST['username']) && isset($_POST['password'])) {
$username = $_POST['username'];
$password = $_POST['password'];

// 含有SQL注入漏洞的查询
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
echo "登录成功";
} else {
echo "用户名或密码错误";
}
}

$conn->close();
?>

一般修复就是对 $password 进行过滤,过滤掉引号那些

文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES['file'])) {
$uploadDirectory = 'uploads/';
$uploadFile = $uploadDirectory . basename($_FILES['file']['name']);

// 检查上传目录是否存在,不存在则创建
if (!is_dir($uploadDirectory)) {
mkdir($uploadDirectory, 0755, true);
}

// 不安全的文件上传
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadFile)) {
echo "文件已成功上传。";
} else {
echo "文件上传失败。";
}
}
?>

未限制后缀名,直接上传,修复方法直接白名单后缀

文件包含

1
2
3
4
5
6
7
8
9
10
<?php
if (isset($_GET['page'])) {
$page = $_GET['page'];

// 不安全的文件包含
include($page . '.php');
} else {
echo "未指定页面。";
}
?>

最简单的方法就是直接删掉 include
当然还有以下几个可以文件包含的函数

1
2
require_once
require

rce

给出最常见的命令执行函数,遇见直接删掉就行

1
2
3
4
5
eval
system
`` // 反引号
exec
shell_exec

反序列化

1
2
unserialize
//还有一些和文件相关的函数

直接删除即可

java

springboot jar

  1. jar包解压
  2. python class2java.py BOOT-INF/classes/com #根据具体路径
  3. IDEA打开BOOT-INF/classes,导入BOOT-INF/lib,开始调试
  4. 加入防御代码,编译运行后,将target里面编译后新的class文件粘贴到原本的jar包中

反序列化

我这里只讲java的原生反序列化,不涉及hessian,kryo等其他序列化器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@PostMapping("/deserialize")
public DataObject deserializeBase64(@RequestBody String base64Data) {
try {
// 解码 Base64 数据
byte[] data = Base64.getDecoder().decode(base64Data);

// 反序列化数据
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data))) {
return (DataObject) ois.readObject();
}
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException("Failed to deserialize object", e);
}
}

大概漏洞原理就是反序列化的时候,会执行需要反序列化的类的readObject,而该类的readObject含有高危代码,或者可以构造出高危漏洞的代码

修复

重写 ObjectInputStream#readClassDescriptor (重新该类是为了防止utf8-overlong绕过)
添加黑名单(白名单最好)

MyObjectInputStream.java(记得加package)

springboot代码也要改成如下(记得import上面的类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@PostMapping("/deserialize")
public DataObject deserializeBase64(@RequestBody String base64Data) {
try {
// 解码 Base64 数据
byte[] data = Base64.getDecoder().decode(base64Data);

// 反序列化数据,修改序列化器
try (ObjectInputStream ois = new MyObjectInputStream(new ByteArrayInputStream(data))) {
return (DataObject) ois.readObject();
}
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException("Failed to deserialize object", e);
}
}

rce

1
2
3
Runtime.getRuntime().exec(var);
java.lang.ProcessBuilder("xxx").start();
new java.lang.UNIXProcess("xxx");

特殊(反射)

1
2
clazz.getDeclaredMethod
method.invoke

修复

直接删除

通用漏洞修复

java总结

不嫌麻烦可以用codeql进行扫描
https://github.com/webraybtl/CodeQLpy
根据教程即可,但是需要安装codeql,有点麻烦
CodeQL的数据库中本质上保存的是与代码相关的AST语法树

python

ssti

漏洞代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@app.route("/", methods=["GET", "POST"])
def index():
ip, port = re.findall(pattern,request.host).pop()
if request.method == 'POST' and request.form.get("word"):
word = request.form.get("word")
if not waf(word):
word = "Hacker!"
else:
word = ""

result = render_template_string(content % (str(ip), str(port), str(word)))
if 'flag{' in result:
result = "Hacker"
return result

该代码从post请求中获取传入的值,最后带入到了 render_template_string(content % (str(ip), str(port), str(word)))
看到最后有个render之类的函数,并且传入的参数可控,就很可能是ssti的漏洞点

修复

1
2
3
# 修复代码
if '{{' in word or '}}' in word or '{%' in word or '%}' in word:
word = "Hacker!"

一般来说过滤掉 {{` , `}} , {%` , `%} ,就可以很大程度防止该漏洞。如果遇到可以编码绕过的形式,那也不是小白能做的了。

反序列化

参考文章:https://goodapple.top/archives/1069

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
from flask import Flask, request, jsonify
import base64
import pickle

app = Flask(__name__)

@app.route('/deserialize', methods=['POST'])
def deserialize():
# 获取 POST 请求中的 Base64 编码数据
data_base64 = request.get_json().get('data')

if not data_base64:
return jsonify({'error': 'No data provided'}), 400

try:
# 解码 Base64 数据
data_bytes = base64.b64decode(data_base64)

# 反序列化数据
data = pickle.loads(data_bytes)

return jsonify({'data': data}), 200
except Exception as e:
return jsonify({'error': str(e)}), 400

if __name__ == '__main__':
app.run(debug=True)

漏洞点是 pickle.loads(data_bytes),data_bytes同样是从post数据中获取,并且进行了base64解码,最后反序列化(pickle.loads)

反序列化原理可以参考网上文章或者我给出的文章链接

修复

与java的反序列化修复类似,重写pickle

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
from flask import Flask, request, jsonify
import base64
import builtins
import io
import pickle

app = Flask(__name__)

safe_builtins = {
'range',
'complex',
'set',
'frozenset',
'slice',
}

class RestrictedUnpickler(pickle.Unpickler):
#重写了find_class方法
def find_class(self, module, name):
# Only allow safe classes from builtins.
if module == "builtins" and name in safe_builtins:
return getattr(builtins, name)
# Forbid everything else.
raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))

def restricted_loads(s):
"""Helper function analogous to pickle.loads()."""
return RestrictedUnpickler(io.BytesIO(s)).load()

@app.route('/deserialize', methods=['POST'])
def deserialize():
# 获取 POST 请求中的 Base64 编码数据
data_base64 = request.get_json().get('data')

if not data_base64:
return jsonify({'error': 'No data provided'}), 400
try:
# 解码 Base64 数据
data_bytes = base64.b64decode(data_base64)

# 反序列化数据
data = restricted_loads(data_bytes)

return jsonify({'data': data}), 200
except Exception as e:
return jsonify({'error': str(e)}), 400

if __name__ == '__main__':
app.run(debug=True)

rce

危险函数,看到直接删了就行了

1
2
3
os.system
eval
os.subprocess

同样有flask举例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from flask import Flask, request, jsonify
import os

app = Flask(__name__)

@app.route('/execute', methods=['POST'])
def execute_command():
# 从请求中获取参数
command = request.get_json().get('command')

if not command:
return jsonify({'error': 'No command provided'}), 400

try:
# 执行命令
result = os.system(command)

return jsonify({'result': result}), 200
except Exception as e:
return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
app.run(debug=True)

修复

直接删除即可

nodejs

原型链污染

1
2
3
4
5
6
7
8
9
10
11
12
13
const merge = (a, b) => {
for (var attr in b) {
if (isObject(a[attr]) && isObject(b[attr])) {
merge(a[attr], b[attr]);
} else {
a[attr] = b[attr];
}
}
return a
}
const clone = (a) => {
return merge({}, a);
}

修复

对传入的参数做一层过滤

1
2
3
4
5
6
7
8
function containsPrototypePollution(obj) {
for (let key in obj) {
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
return true;
}
}
return false;
}

总结

上面总结的漏洞只是该语言的冰山一角,只是挑了部分常见简单的来说
还有golang,c#的漏洞,但是上面那些语言更常见,就挑这些来说了,实在不知道怎么修复,但是能找到漏洞点,那就删掉