├── pic
├── admin.png
├── config.png
├── files.png
├── get.png
├── headers.png
├── result.png
└── test.png
├── readme.md
└── waffffff
├── admin.php
├── api.php
├── check.php
├── config.php
├── functions.php
├── layui
├── css
│ ├── layui.css
│ ├── layui.mobile.css
│ └── modules
│ │ ├── code.css
│ │ ├── laydate
│ │ └── default
│ │ │ └── laydate.css
│ │ └── layer
│ │ └── default
│ │ ├── icon-ext.png
│ │ ├── icon.png
│ │ ├── layer.css
│ │ ├── layer_bak.css
│ │ ├── loading-0.gif
│ │ ├── loading-1.gif
│ │ └── loading-2.gif
├── font
│ ├── iconfont.eot
│ ├── iconfont.svg
│ ├── iconfont.ttf
│ └── iconfont.woff
├── images
│ └── face
│ │ ├── 0.gif
│ │ ├── 1.gif
│ │ ├── 10.gif
│ │ ├── 11.gif
│ │ ├── 12.gif
│ │ ├── 13.gif
│ │ ├── 14.gif
│ │ ├── 15.gif
│ │ ├── 16.gif
│ │ ├── 17.gif
│ │ ├── 18.gif
│ │ ├── 19.gif
│ │ ├── 2.gif
│ │ ├── 20.gif
│ │ ├── 21.gif
│ │ ├── 22.gif
│ │ ├── 23.gif
│ │ ├── 24.gif
│ │ ├── 25.gif
│ │ ├── 26.gif
│ │ ├── 27.gif
│ │ ├── 28.gif
│ │ ├── 29.gif
│ │ ├── 3.gif
│ │ ├── 30.gif
│ │ ├── 31.gif
│ │ ├── 32.gif
│ │ ├── 33.gif
│ │ ├── 34.gif
│ │ ├── 35.gif
│ │ ├── 36.gif
│ │ ├── 37.gif
│ │ ├── 38.gif
│ │ ├── 39.gif
│ │ ├── 4.gif
│ │ ├── 40.gif
│ │ ├── 41.gif
│ │ ├── 42.gif
│ │ ├── 43.gif
│ │ ├── 44.gif
│ │ ├── 45.gif
│ │ ├── 46.gif
│ │ ├── 47.gif
│ │ ├── 48.gif
│ │ ├── 49.gif
│ │ ├── 5.gif
│ │ ├── 50.gif
│ │ ├── 51.gif
│ │ ├── 52.gif
│ │ ├── 53.gif
│ │ ├── 54.gif
│ │ ├── 55.gif
│ │ ├── 56.gif
│ │ ├── 57.gif
│ │ ├── 58.gif
│ │ ├── 59.gif
│ │ ├── 6.gif
│ │ ├── 60.gif
│ │ ├── 61.gif
│ │ ├── 62.gif
│ │ ├── 63.gif
│ │ ├── 64.gif
│ │ ├── 65.gif
│ │ ├── 66.gif
│ │ ├── 67.gif
│ │ ├── 68.gif
│ │ ├── 69.gif
│ │ ├── 7.gif
│ │ ├── 70.gif
│ │ ├── 71.gif
│ │ ├── 8.gif
│ │ └── 9.gif
├── lay
│ └── modules
│ │ ├── carousel.js
│ │ ├── code.js
│ │ ├── colorpicker.js
│ │ ├── element.js
│ │ ├── flow.js
│ │ ├── form.js
│ │ ├── jquery.js
│ │ ├── laydate.js
│ │ ├── layedit.js
│ │ ├── layer.js
│ │ ├── laypage.js
│ │ ├── laytpl.js
│ │ ├── mobile.js
│ │ ├── rate.js
│ │ ├── slider.js
│ │ ├── table.js
│ │ ├── tree.js
│ │ ├── upload.js
│ │ └── util.js
├── layui.all.js
└── layui.js
└── waf.php
/pic/admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NonupleBroken/AWD_PHP_WAF/95bc34dbb0b3979fb68c431388608fcc419a24ed/pic/admin.png
--------------------------------------------------------------------------------
/pic/config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NonupleBroken/AWD_PHP_WAF/95bc34dbb0b3979fb68c431388608fcc419a24ed/pic/config.png
--------------------------------------------------------------------------------
/pic/files.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NonupleBroken/AWD_PHP_WAF/95bc34dbb0b3979fb68c431388608fcc419a24ed/pic/files.png
--------------------------------------------------------------------------------
/pic/get.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NonupleBroken/AWD_PHP_WAF/95bc34dbb0b3979fb68c431388608fcc419a24ed/pic/get.png
--------------------------------------------------------------------------------
/pic/headers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NonupleBroken/AWD_PHP_WAF/95bc34dbb0b3979fb68c431388608fcc419a24ed/pic/headers.png
--------------------------------------------------------------------------------
/pic/result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NonupleBroken/AWD_PHP_WAF/95bc34dbb0b3979fb68c431388608fcc419a24ed/pic/result.png
--------------------------------------------------------------------------------
/pic/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NonupleBroken/AWD_PHP_WAF/95bc34dbb0b3979fb68c431388608fcc419a24ed/pic/test.png
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | 针对 AWD 中 php 网页设计的 waf,主要有三个功能:
2 | 1. 记录所有 status_code==200 的请求,记录的字段包括:时间、IP、请求文件、请求方法、headers、cookies、GET、POST、FILES。
3 | 2. 拦截预先设置的攻击流量,并记录是否被拦截,以及拦截原因。
4 | 3. 可视化浏览所有流量记录,并可根据 IP 和时间进行搜索。
5 |
6 | # 使用
7 |
8 | 将 waf 文件夹直接复制到 web 网站根目录下即可。
9 |
10 | ## 配置
11 |
12 | 基本配置在 config.php 下:
13 |
14 | 
15 |
16 | * PASSWORD:流量查看界面的密码的 sha256 值。
17 | * DATA_PATH:日志、IP 存储的文件夹的绝对路径,php 进程用户(如 www-data)必须对该文件夹具有可写权限。否则无法记录攻击流量。设置好后可以运行 check.php 检查权限。
18 | * LOG_NAME:所有流量记录的日志名称前缀。
19 | * LOG_TIME_INTERVAL:每隔多少秒换新的文件存储日志,推荐为每轮的时间。
20 | * IP_NAME:攻击源 IP 记录的存储名称。
21 | * IGNORE_REQUESTS_WITH_NO_PARAMS:是否忽略没有 GET,POST 和 FILES 参数的请求。
22 | * TRY_BASE64ENCODE_WAF:拦截时先尝试 base64 解码,若解码成功,则根据解码后数据拦截。
23 |
24 | waf 规则配置在 functions.php 中的 waf_working 函数中,注意转义。
25 |
26 | ## 上下waf
27 |
28 | 在 web 网站根目录下运行命令。一定要使用 waf 所在的绝对路径并注意转义。
29 | ```bash
30 | 上waf:
31 | $ find . -path ./waffffff -prune -o -type f -name "*.php" -print | xargs sed -i "s/
12 |
13 |
14 |
15 |
16 |
17 | Ph0en1x Admin Manage
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
87 |
88 |
232 |
233 |
--------------------------------------------------------------------------------
/waffffff/api.php:
--------------------------------------------------------------------------------
1 | $value) {
51 | $tmp[$key] = stripArr($tmp[$key]);
52 | }
53 | $tmp['files_data'] = json_encode($tmp['files_data'], JSON_UNESCAPED_UNICODE);
54 |
55 | $tmp['wafed_result'] = stripStr($tmp['wafed_result']);
56 |
57 | $data[] = $tmp;
58 |
59 | if (!in_array($tmp['user_IP'], $ips)) {
60 | $ips[] = $tmp['user_IP'];
61 | }
62 | }
63 | }
64 | }
65 | }
66 | $data = array_reverse($data);
67 |
68 | $count = count($data);
69 |
70 | $array = compact("code", "msg", "count", "data");
71 |
72 | // 写入ip
73 | sort($ips);
74 |
75 | $ipFile = DATA_PATH.'/'.IP_NAME;
76 | if (!file_exists($ipFile)) {
77 | touch($ipFile);
78 | }
79 | $res = '';
80 | foreach ($ips as $ip) {
81 | $res .= ($ip.PHP_EOL);
82 | }
83 | file_put_contents($ipFile, $res);
84 |
85 | return json_encode($array, JSON_UNESCAPED_UNICODE);
86 | }
87 |
88 | if (isset($_GET['cmd'])) {
89 | if ($_GET['cmd'] === 'load_waf_record') {
90 | $IP = isset($_GET['ip'])? $_GET['ip']: 'all';
91 | $TIME = isset($_GET['time'])? $_GET['time']: 'all';
92 | echo load_waf_record($IP, $TIME);
93 | }
94 | }
95 | ?>
--------------------------------------------------------------------------------
/waffffff/check.php:
--------------------------------------------------------------------------------
1 | ";
10 | if (file_put_contents($name, $content)) {
11 | echo "file_put_contents --- ok.
";
12 | if (file_get_contents($name) === $content) {
13 | echo "file_get_contents --- ok.
";
14 | if (file($name)[0] === $content) {
15 | echo "file --- ok.
";
16 | if (unlink($name)){
17 | echo "unlink --- ok.
";
18 | echo "all done. gogogo!";
19 | }
20 | else {
21 | echo "unlink --- failed.
";
22 | }
23 | }
24 | else {
25 | echo "file --- failed.
";
26 | }
27 | }
28 | else {
29 | echo "file_get_contents --- failed.
";
30 | }
31 | }
32 | else {
33 | echo "file_put_contents --- failed.
";
34 | }
35 | }
36 | else {
37 | echo "touch --- failed.
";
38 | }
39 | ?>
--------------------------------------------------------------------------------
/waffffff/config.php:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/waffffff/functions.php:
--------------------------------------------------------------------------------
1 | $value) {
11 | if (substr($name, 0, 5) == 'HTTP_') {
12 | $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
13 | }
14 | }
15 | return $headers;
16 | }
17 | }
18 |
19 | // xss过滤
20 | function stripStr($str) {
21 | if (get_magic_quotes_gpc()) {
22 | $str = stripslashes($str);
23 | }
24 | return addslashes(htmlspecialchars($str, ENT_QUOTES, 'UTF-8'));
25 | }
26 |
27 | function stripArr($arr) {
28 | $new_arr = array();
29 | foreach($arr as $k => $v) {
30 | $new_arr[stripStr($k)] = stripStr($v);
31 | }
32 | return $new_arr;
33 | }
34 |
35 | //尝试base64解码
36 | function tryBase64Decode($arr) {
37 | if (isset($arr) && count($arr)>0) {
38 | $isChanged = 0;
39 | $new_arr = array();
40 | foreach ($arr as $k => $v) {
41 | $decoded_v = "";
42 | if (isBase64Formatted($v)) {
43 | $decoded_v = base64_decode($v);
44 | $isChanged = 1;
45 | }
46 | $new_arr[$k] = $decoded_v;
47 | }
48 |
49 | if ($isChanged) {
50 | return $new_arr;
51 | }
52 | else {
53 | return $arr;
54 | }
55 | }
56 | else {
57 | return $arr;
58 | }
59 | }
60 |
61 | // 判断string是否为base64编码(判断方法:解码后为可见字符串)
62 | function isBase64Formatted($str) {
63 | if (preg_match('/^[A-Za-z0-9+\/=]+$/', $str)) {
64 | if ($str == base64_encode(base64_decode($str))) {
65 | if (preg_match('/^[A-Za-z0-9\x00-\x80~!@#$%&_+-=:";\'<>,\/"\[\]\\\^\.\|\?\*\+\(\)\{\}\s]+$/', base64_decode($str))) {
66 | return true;
67 | }
68 | }
69 | }
70 | return false;
71 | }
72 |
73 | // waf
74 | function waf_working($get_data, $post_data, $files_data) {
75 | if (TRY_BASE64ENCODE_WAF) {
76 | $get_data = tryBase64Decode($get_data);
77 | $post_data = tryBase64Decode($post_data);
78 | }
79 | // 绝对不能出现的字符
80 | $pattern1 = "\^|\'|\.\.\/|\./|>|&|;";
81 | // 不能作为关键字出现
82 | $pattern2 = "select|union|load_file|outfile|dumpfile";
83 | $pattern2.= "|file_get_contents|file_put_contents|fwrite|fopen|fread|file|readfile|popen|scandir";
84 | $pattern2.= "|curl|system|eval|assert|exec|shell_exec";
85 | $pattern2.= "|cat|less|head|tail";
86 | $vpattern1 = explode("|", $pattern1);
87 | $vpattern1[] = "\|"; // 这里由于'|'没法转义,因此要用的话直接加进去
88 | $vpattern2 = explode("|", $pattern2);
89 |
90 | // GET
91 | foreach ($get_data as $k => $v) {
92 | foreach ($vpattern1 as $value) {
93 | if (preg_match("/$value/i", $v)) {
94 | return 'GET - '.$k.' - '.$v.' - '.stripslashes($value);
95 | }
96 | }
97 | foreach ($vpattern2 as $value) {
98 | if (preg_match("/\b$value\b/i", $v)) {
99 | return 'GET - '.$k.' - '.$v.' - '.stripslashes($value);
100 | }
101 | }
102 | }
103 |
104 | // POST
105 | foreach ($post_data as $k => $v) {
106 | foreach ($vpattern1 as $value) {
107 | if (preg_match("/$value/i", $v)) {
108 | return 'POST - '.$k.' - '.$v.' - '.stripslashes($value);
109 | }
110 | }
111 | foreach ($vpattern2 as $value) {
112 | if (preg_match("/\b$value\b/i", $v)) {
113 | return 'POST - '.$k.' - '.$v.' - '.stripslashes($value);
114 | }
115 | }
116 | }
117 |
118 | $pattern1 = "\.php";
119 | $pattern2 = "<\?php|language=\"php\"|