简单的web加固

前言

ciscn初赛过了就要准备分区赛了,当然就要来练习awd plus了,awdp最重要的一环还是加固,因此这篇博客来总结一下一些简单常用的web加固。

常见加固汇总

sql注入

关于sql注入加固的方式有许多不同的方法,这里就简单介绍几个常用方法。

  1. 转义法
    转义法就是将我们输入的值进行转义处理,让引号之类的特殊符号被当做输入内容,从而防止引号的恶意闭合导致sql注入。php中常见的转义函数如下:

    1
    2
    3
    addslashes() 全版本通用
    mysql_real_escape_string() 在php5.5中已经弃用,并在php7中被删除
    mysql_escape_string() PHP 4 >= 4.0.3, PHP 5
  2. 过滤法
    过滤法,也就是设置黑名单,阻止一些恶意语句的传入。当后端程序检测到输入的内容存在黑名单中时,即立刻终止程序,从而起到防御的作用。

常用waf:

1
2
3
4
if(preg_match("/xml|extractvalue|regexp|copy|read|file|create|grand|dir|insert|link|server|drop|=|>|<|;|select|union|flag|ascii|subm|right|\'|\^|\||\ /i",$username)){
die("no");
}
//使用preg_replace也可,具体要看攻击的exp或payload形式

XSS攻击

对于XSS攻击的防守主要还是以过滤为主。对于XSS攻击最好的过滤方式还得是过滤<script>"/等等敏感字符,以防止各种各样奇怪的绕过方法:

1
2
3
4
if(preg_match("/script|\<|\>|\/|\\|\"|document|console|alert|src|xml|\+|_|data|cookie|flag|var/i",$username)){
die("no");
}
//使用preg_replace也可,具体要看攻击的exp或payload形式

DVWA中对于XSS攻击的防御采取了设置token的方法。其实我们也可以通过编码转化来进行防御,对输入的值进行一次base64解码等方式来进行防御也是一种可行的策略。

任意文件包含/读取

存在这类目录很多都是因为没有对输入的值进行控制,导致在引用或者读取文件时被攻击者以相对路径或者伪协议的方式直接读取到了文件。因此此类漏洞无脑过滤./和伪协议就可以了:

1
2
3
4
if(preg_match("/data|ph|file|\:|\/|\.|\+|flag|phar/i",$username)){
die("no");
}
//使用preg_replace也可,具体要看攻击的exp或payload形式

DVWA中针对此类漏洞做出了无懈可击的防御——白名单机制。或者还有一种思路是控制输出内容,但是不知道这种思路在awdp中能不能实现。

Upload

关于文件上传就有很多值得说到的东西了,前端的MINE,后端的waf都是进行防御的有效手段。不过必须要注意的是图片码的防御,不能让.htacess文件和.user.ini文件被上传,并且一定要对图片进行二次渲染,杀死藏匿于图片中的木马。

关于waf,除了常规的后缀黑名单与白名单,更重要的是对上传文件内容的过滤,对于各种一句话木马bypass是绝对不能姑息的。同样,对于文件路径的保护也是防止文件上传漏洞发生的重要手段。

最后一种方法便是设置权限,upload文件夹下的文件取消执行权限,这样可以使上传的脚本不能够被执行。

总之,关于upload漏洞的防护加固方式是多样的,我们可以根据exp进行重点针对。

总结

上面几个漏洞的加固都是常规的php漏洞,还是比较简单的,打打分区赛暂时还行,不像总决赛什么加固都有,python、java一个不漏。

Ezsql

打开网页发现是一个登录框,测试sql万能密码发现登陆成功:

1
admin' or 1=1#

那么连接ssh,进入/var/www/html目录,查看index.php文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
error_reporting(0);
include 'dbConnect.php';
$username = $_GET['username'];
$password = $_GET['password'];
if (isset($_GET['username']) && isset($_GET['password'])) {
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = $mysqli->query($sql);
if (!$result)
die(mysqli_error($mysqli));
$data = $result->fetch_all(); // 从结果集中获取所有数据
if (!empty($data)) {
echo '登录成功!';
} else {
echo "用户名或密码错误";
}
}
?>

一点过滤都没有,那么我们只用转义法进行加固:

1
2
$username = addslashes($username);
$password = addslashes($password);

加固后返回测试,发现登录失败,那么我们进行check,返回true,在/flag中获取flag。

[网鼎杯 2020 半决赛]faka

这题没在加固题中,但是当时网鼎杯半决赛也是awdp,因此直接拿来做。

首先打一下这个题,查看源码,发现一个sql文件,源码中发现admin路由,发现需要登录。因此查看数据表内容,在system_user找到用户密码的md5值,用somd5解密,密码为admincccbbb123。

登录后台成功后,去源码中搜关键函数,在/manage/controller/Backup.php`中发现文件读取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function downloadBak() {
$file_name = $_GET['file'];
$file_dir = $this->config['path'];
if (!file_exists($file_dir . "/" . $file_name)) { //检查文件是否存在
return false;
exit;
} else {
$file = fopen($file_dir . "/" . $file_name, "r"); // 打开文件
// 输入文件标签
header('Content-Encoding: none');
header("Content-type: application/octet-stream");
header("Accept-Ranges: bytes");
header("Accept-Length: " . filesize($file_dir . "/" . $file_name));
header('Content-Transfer-Encoding: binary');
header("Content-Disposition: attachment; filename=" . $file_name); //以真实文件名提供给浏览器下载
header('Pragma: no-cache');
header('Expires: 0');
//输出文件内容
echo fread($file, filesize($file_dir . "/" . $file_name));
fclose($file);
exit;
}
}

没有过滤,那么我们直接构建payload:

1
/manage/backup/downloadbak?file=../../../../../../../../../../flag.txt

获取flag。

其实看了别人的wp,发现还有文件上传漏洞可以利用,但是那个利用十分复杂,这里就不多讲了。主要讲一下加固,其实也很简单,过滤..../就可以了。

加固代码如下:

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
function downloadBak() {
$file_name = $_GET['file'];
$waf = array("..","../");
if(in_array($file, $waf)){
die("impossible");
}
$file_dir = $this->config['path'];
if (!file_exists($file_dir . "/" . $file_name)) { //检查文件是否存在
return false;
exit;
} else {
$file = fopen($file_dir . "/" . $file_name, "r"); // 打开文件
// 输入文件标签
header('Content-Encoding: none');
header("Content-type: application/octet-stream");
header("Accept-Ranges: bytes");
header("Accept-Length: " . filesize($file_dir . "/" . $file_name));
header('Content-Transfer-Encoding: binary');
header("Content-Disposition: attachment; filename=" . $file_name); //以真实文件名提供给浏览器下载
header('Pragma: no-cache');
header('Expires: 0');
//输出文件内容
echo fread($file, filesize($file_dir . "/" . $file_name));
fclose($file);
exit;
}
}