漏洞修复必备手册之场景代码详解

  • A+
所属分类:安全文章
漏洞修复必备手册之场景代码详解

网安教育

培养网络安全人才

技术交流、学习咨询





1、 跨站脚本XSS



1.1反射xss


1.1.1 输出在html 标签内或者普通属性(非href、非事件类)

调用如下的HtmlEncode 函数进行编码,php 示例代码,其他语言可以参照实现。

 1function HtmlEncode($str)
2
3
{
4
5    $str = str_replace("&","&", $str);
6
7    $str = str_replace(">",">", $str);
8
9    $str = str_replace("<","&lt;", $str);
10
11    $str = str_replace(""","&quot;", $str);
12
13    $str = str_replace("'","&#39;",  $str);
14
15    $str = preg_replace("/s+/","&#32;", $str);
16
17    return $str;
18
19}


注:为了预防业务将参数输出至属性值时未使用引号包裹的情况,这里自己实现的HtmlEncode 也将空格编码。


1.1.2 输出在html 标签的 href 属性内

一般来说,如果变量是完整的url,应该先检查下是否以^http开头,且目的域名是允许的域名列表内,以保证不会出现伪协议类的XSS攻击。接着使用 HtmlEncode编码下;或者因为此处是地址栏,可以用 php标准函数urlencode 编码变量。


1.1.3 输出在html 标签的事件属性内(如onXX 事件)

使用 jsencode(uUUUU) 编码,php 示例代码,其他语言可以参照实现。

 1function jsencode($str)
2
3
{
4
5    $arr = array();
6
7    $str_len = strlen($str);
8
9    $need_encode = "<>"&#`()[]';";
10
11    for($i = 0; $i < $str_len; $i++)
12
13    {
14
15        if (strpos($need_encode, $str[$i]))
16
17        {
18
19            $arr[$i] = "\u00" . bin2hex($str[$i]);
20
21       }
22
23       else
24
25        {
26
27            $arr[$i] = $str[$i];
28
29        }
30
31    }
32
33    return join("", $arr);
34
35 }


1.1.4 在富文本框内进行过滤

参考 这里 进行标签和属性的白名单过滤。


1.2 存储XSS


同反射XSS,在输出变量时参照如上情形描述。


1.3 DOMXSS


在"$var" 输出到<script> 时,应该执行一次 jsencode(uUUUU);其次,在document.write 输出到页面 html 页面时,要分具体情况对待:如果是输出到事件或者脚本,则要再做一次 jsEncode;如果是输出到 html 内容或者属性,则要再做一次 HtmlEncode。


如下情况属于后者,即 HtmlEncode (jsencode($var))

1<script>
2
3var x = "$var";
4
5document.write("<a href='"+x+"' >test</a>");
6
7
</script>


Javascript 函数代码示例如下:

 1function jsencode(str{
2
3    var arr = [];
4
5    var need_encode = "<>"&#`()[]';";
6
7    for (var i = 0; i < str.length; i++) {
8
9
10
11        if (need_encode.indexOf(str[i]) != -1)
12
13        {
14
15            arr[i] = ("\u00" + str.charCodeAt(i).toString(16)).slice(-6);
16
17        }
18
19        else
20
21        {
22
23            arr[i] = str[i];
24
25        }
26
27    }
28
29    return arr.join("");
30}
31
32
33
34function HtmlEncode(sStr)
35
36
{
37
38    sStr = sStr.replace(/&/g,"&amp;");
39
40    sStr = sStr.replace(/>/g,"&gt;");
41
42    sStr = sStr.replace(/</g,"&lt;");
43
44    sStr = sStr.replace(/"/g,"&quot;");
45
46    sStr = sStr.replace(/'/g,"&#39;");
47
48    sStr = sStr.replace(/s+/g,"&#32;");
49
50    return sStr;
51
52}


在使用location.href / location.replace() / location.assign() 等函数实现前端跳转时不止要考虑url 任意跳转的问题,如1.1.2 所说也要避免伪协议引起的xss攻击。


1.4 flash xss


建议不再使用的swf请下线,其他有漏洞的swf请更新至官方最新版,或者用其他功能类似swf 替代实现。





2、 跨站请求伪造CSRF



2.1 校验refer


Refer 校验需要严格的正则,比如 /^http://www.qq.com/index.html$/,否则可能被绕过。但是某些情况下发出的情况Refer 为空甚至以前曾经出现过flash请求可以伪造Refer,故更敏感的一些操作建议使用验证token方式。


2.2 验证token


即在页面埋下隐藏的动态token值,后端逻辑对这个token 值进行验证,如果不正确则直接退出。php 代码示例如下:

 1<?php
2
3
4
5session_start();
6
7if (isset($_SESSION['token']) && isset($_POST['username'])) {
8
9    if (empty($_POST['token']) || $_POST['token'] != $_SESSION['token']) {
10
11        header('Location: http://localhost/error.php?token=' . $_SESSION['token']);
12
13        exit(-1);
14
15    }
16
17}
18
19
20
21$token   = md5(time());
22
23$_SESSION['token'] = $token;
24
25?>

26
27
28
29<html>
30
31<head>
32
33    <title>test with csrf token</title>
34
35</head>
36
37<body>
38
39<form method="post" action="/csrf.php" id="form">
40
41    <div>
42
43        <input name="username" type="text" id="username" style="width:270px;"/>
44
45        <input type="submit" name="btnSearch" value="Search" id="btnSearch" />
46
47        <input type="hidden" name="token" id="token" value="<?php echo $token;?>" />
48
49    </div>
50
51</form>
52
53
54
55<br/>
56
57</body>
58
59</html>


2.3 验证码


在特别关键的操作建议启用,其他操作建议预埋验证码,紧急时刻(如出现CSRF蠕虫)可以临时启用。





3、SQL 注入



3.1 首选绑定参数的方式进行sql 操作


PHP5中,增加了MySQL支持,提供了mysqli扩展:

PHP手册地址:http://php.net/mysqli

 1<?php
2
3// retrieve the user's input
4
5$animalName = $_POST['animalName'];
6
7// connect to the database
8
9$connect    = mysqli_connect('localhost''username''password''database');
10
11if (!$connect)
12
13    exit('connection failed:  ' . mysqli_connect_error());
14
15// create a query statement resource
16
17$stmt = mysqli_prepare($connect, "SELECT intelligence FROM animals WHERE name = ?");
18
19if ($stmt) {
20
21    // bind the substitution to the statement
22
23    mysqli_stmt_bind_param($stmt, "s", $animalName);
24
25    // execute the statement
26
27    mysqli_stmt_execute($stmt);
28
29    // retrieve the result...
30
31    mysqli_stmt_bind_result($stmt, $intelligence);
32
33    // ...and display it
34
35    if (mysqli_stmt_fetch($stmt)) {
36
37        print "A $animalName has $intelligence intelligence.n";
38
39    } else {
40
41        print 'Sorry, no records found.';
42
43    }
44
45    // clean up statement resource
46
47    mysqli_stmt_close($stmt);
48
49}
50
51mysqli_close($connect);
52
53?>


3.2 检测参数类型,添加转义

如果php版本太低,或者改造代码成本比较大,在使用参数拼接方式实现sql 操作时,务必做到以下两点:


3.2.1 检查参数类型

当用户输入的为数字时可以使用如下方式:

使用is_int()函数(或is_integer()或is_long()函数)

使用gettype()函数

使用intval()函数

使用settype()函数

检查用户输入字符串的长度使用strlen()函数。

检查日期或时间是否是有效的,可以使用strtotime()函数。


3.2.2 查询之前进行转义操作

对于一个已经存在的程序来说,可以写一个通用函数来过滤:

1function safe($string)
2
3
{
4
5    return "'" . mysql_real_escape_string($string) . "'";
6
7}


调用方式:

1$variety = safe($_POST[' variety ']);
2
3$query   = "SELECT * FROM wines WHERE variety=" . $variety;


注:mysql_real_escape_string 必须在(PHP 4 >= 4.3.0, PHP 5)的情况下才能使用,否则只能用 mysql_escape_string,转义字符有:x00 , n , r , , ' , " and x1a。

Safe 函数中需要将转义之后的字符串用引号包裹起来(对于int类型说查询结果一致),否则黑客本来就不用考虑去闭合引号,转义操作也等于没有效果。

如果数据库字符集是gbk,可能存在宽字节绕过问题,需要在查询之前设置一下character_set_client,如下所示:

1mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary"$conn);






4、文件包含漏洞



4.1 本地文件包含


php中可以使用 open_basedir 将用户文件访问限制在指定的区域。如将文件访问限制在 /dir/user/ 中,在php.ini中设置 open_basedir = /dir/user/。

对包含文件的名称、路径进行严格限制和过滤(建议白名单方式),避免被篡改为恶意文件,单纯过滤 ”../” 等相对路径串很可能会被绕过。过滤以下字符(以逗号分隔):

1../, %2e%2e%2f, %2e%2e/, ..%2f, %2e%2e%5c, %2e%2e, ..%5c, %252e%252e%255c, ..%c0%af(仅windows需要), ..%c1%9c(仅windows需要)


4.2 远程文件包含

关闭allow_url_fopen、allow_url_include。





5、命令执行漏洞



对于传入的变量做过滤,对于 n $ & ; | ' " ( ) `(反单引号) 过滤或转义这些特殊字符。





6、SSRF 服务端请求伪造



限制 C(libcurl)/php(cURL) 允许的协议

如设置CURLPROTO_HTTP选项,仅仅允许http和https请求,可以防止类似于file:///, gopher://, ftp:// 等引起的问题。


限制访问内网

从url 中提取出域名 www.test.com ,解析域名,获得域名指向的地址 X.X.X.X

检查地址是否为内网地址段:10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.0/8等,

如果是内网地址则屏蔽;

如果不是内网地址,设置 CURLOPT_RESOLVE(libcurl),使libcurl 将域名解析到我们刚才解析出的ip 地址进行访问,即真正发起请求时不再进行dns解析,避免被 dns rebinding 绕过。


避免30x 跳转绕过

设置不跟随跳转,即设置 CURLOPT_FOLLOWLOCATION 为false。如果一定要跟随跳转,这里因为使用了库函数,故不能自己在跟随跳转前判断下域名解析的目标ip 是否是内网(如2),但可以通过设置 CURLOPT_OPENSOCKETFUNCTION 回调函数,在socket 创建之前先校验目标地址。

1// curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, opensocket_callback);


 1curl_socket_t opensocket_callback(void *clientp, curlsocktype purpose,
2 struct curl_sockaddr *addr)
3{
4 struct sockaddr_in *addr_in = (struct sockaddr_in *) &addr->addr;
5 unsigned int uip = ntohl(addr_in->sin_addr.s_addr);
6
7 char ipbuf[50];
8 inet_ntop(addr_in->sin_family, &addr_in->sin_addr, ipbuf, sizeof(ipbuf));
9 INF("Connect IP: %sn", ipbuf);
10
11 if ((uip >= 0x7F000000 && uip <= 0x7FFFFFFF) ||
12     (uip >= 0x0A000000 && uip <= 0x0AFFFFFF) ||
13     (uip >= 0xAC100000 && uip <= 0xAC1FFFFF) ||
14     (uip >= 0xC0A80000 && uip <= 0xC0A8FFFF) ||
15     (uip == 0x00000000 || uip == 0xFFFFFFFF))
16 {
17     //过滤来自内网的访问
18     WRN("target ip is illegal.n");
19     return CURL_SOCKET_BAD;
20 }
21
22 return socket(addr->family, addr->socktype, addr->protocol);
23}


这样,每当libcurl 试图创建socket 连接某个服务器时,都会先执行 opensocket_callback 回调函数。若目标地址不合法,则可以在这个回调函数中返回CURL_SOCKET_BAD,libcurl 也会因此无法建立连接返回失败。




7、文件上传漏洞



7.1 目录安全配置


如果Apache以daemon普通用户启动,则黑客通过网站漏洞入侵服务器后,将获得Apache的daemon权限,因此需要确认网站web目录和文件的属主与Apache启动用户不同,防止网站被黑客恶意篡改和删除。

a) 网站web目录和文件的属主可以设置为root等(非Apache启动用户)。

b) Web目录权限统一设置为755,web文件权限统一设置为644(cgi文件若需执行权限可设置为755),只有上传目录等需要可读可写权限的目录可以设置为777(目录需要有执行权限才可进入)。

目录默认不可写,可写目录不解析,Web Server非root,管理页面不对外。


7.2判断文件类型


可以结合使用mime type、后缀方式、文件头部(getimagesize /exif_imagetype),强烈推荐白名单方式。


7.3 改写文件名和路径


使用随机数改写文件名和文件路径;或者把文件放在非web 目录下(或者统一的一个文件服务器),且设置open_basedir 以避免被文件包含。


7.4上传目录只允许访问特定类型的文件


配置文件如下:

1<Files ^(*.jpeg|*.jpg|*.png|*.gif)>
2
3order deny,allow
4
5deny from all
6
7</Files>





8、管理后台



管理后台默认不对外开放,如果一定要对外开放,需要有安全配置。

对于管理目录,需要做到只允许合法ip(一般内网)可以访问,nginx限制白名单ip访问的配置如下:

1location ~ ^/private/ {
2
3allow 192.168.1.0/24;
4
5deny all;
6
7}


管理目录建议启用密码认证,密码认证依靠Web应用自身的认证机制。如果Web应用无认证机制,可启用nginx(apache同理)的密码认证机制,配置如下:

 1location ^~ /soft/ {
2
3location ~ .*.(php|php5)?$ {
4
5fastcgi_pass unix:/tmp/php-cgi.sock;#这里按照你自己的设置
6
7fastcgi_index index.php;
8
9include fcgi.conf;
10
11}
12
13auth_basic "Authorized users only";
14
15auth_basic_user_file 这里写前面脚本返回的文件路径;
16}
漏洞修复必备手册之场景代码详解
来源:https://www.hacking8.com/MiscSecNotes/xiufu.html#title-12


开源聚合网安训练营

战疫期间,开源聚合网络安全基础班、实战班线上全面开启,学网络安全技术、升职加薪……有兴趣的可以加入开源聚合网安大家庭,一起学习、一起成长,考证书求职加分、升级加薪,有兴趣的可以咨询客服小姐姐哦!

漏洞修复必备手册之场景代码详解

加QQ(1271375291)找小姐姐私聊哦



精选文章


环境搭建
Python
学员专辑
信息收集
CNVD
安全求职
渗透实战
CVE
高薪揭秘
渗透测试工具
网络安全行业
神秘大礼包
基础教程
我们贴心备至
用户答疑
 QQ在线客服
加入社群
QQ+微信等着你

漏洞修复必备手册之场景代码详解


我就知道你“在看”
漏洞修复必备手册之场景代码详解

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: