ctf-web
ctf-web
- 信息搜集
- 认证绕过
- SQL注入
- 文件上传
- 文件包含
- PHP代码审计
信息搜集
-
源码泄露
-
页面源代码
-
敏感文件泄漏
- 备份文件(.swp/.bak/.beifen/~/phps等)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MGonEuLW-1604453612546)(https://i.loli.net/2020/11/02/kUboAxLhtRvD85z.png)]
- 数据库(mdb)
- 压缩包(zip/tar.gz//DS_Store/WEB-INF/web.xml/cvs/Bazaar/bzr)
-
-
robots.txt泄漏
-
404页面泄漏
-
协议头泄漏
-
HTTP请求与响应头
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-59VEVNT8-1604453612550)(https://i.loli.net/2020/11/02/dMPgqGHOknzDaW9.png)]
- JS代码隐藏
- GIT泄漏
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-67GrN3mI-1604453612554)(https://i.loli.net/2020/11/02/otpkwcUILCgh6ay.png)]
认证绕过
HTTP协议基础
-
HTTP请求(Requests)
一个HTTP请求包含三个部分:
- 方法,URL,协议/版本(Method-URI-Protocol/Version)
- 请求包头(Requests headers)
- 实体包(Entity body)
-
HTTP响应(Responses)
一个HTTP响应也包含三个部分:
- 协议状态代码描述(Protocol-Status code-Description)
- 响应包头(Response headers)
- 实体包(Entity body)
HTTP请求报文
HTTP请求由请求行、消息报头、请求正文三个部分组成。
- 方法,URL,协议/版本(Method-URI-Protocol/Version)
- 消息报头(Request headers)
- 请求正文(Entity body)
HTTP请求方法
DELETE | DELETE方法用于请求资源服务区删除指定的资源 |
---|---|
TRACE | TRACE方法一般用于激发一个远程应用层的请求消息回路 |
CONNECT | 为了能动态的切换到隧道的代理 |
OPTIONS | OPTIONS方法用于请求获取URI标识的资源在请求\响应的通信过程中可以使用的功能选项 |
HTTP请求首部
- Host:主要用于指定被请求支援的Internet主机和端口号
- User-Agent:向服务端传递客户端操作系统、浏览器、和其他属性
- Referer:包含一个URL,代表当前URL的上一个URL
- Cookie:是一段文本,通常来表示请求者的身份
- Range:Range可以请求实体部分内容,多线程下载一定会用到此请求头
- x-forward-for:即XFF头,代表请求端的IP,也可以是多个,中间用逗号隔开
- Accept:用于指定客户端接收哪些MIME类型的信息
- Accept-Charset:用于指定客户端接收的字符集
- 信息:就是实体内容的属性,包括实体信息类型,长度,压缩方法,最后一次修改时间等
- Content-Type:用于向接收方指示实体的介质类型
- Content-Encoding:被用作媒体类型的修饰符,表示了已经被用到实体正文的附加内容编 码,想要获得content-type报头域中所引用的媒体类型,必须采用相应的解码机制
- Content-Length:用于指明实体正文的长度,以字节方式存储的十进制数字来表示
- Last-Modified:用于指示资源的最好修改时间和日期
HTTP响应报文
HTTP 响应(Responses) 也包含三个部分:状态行、 消息报头、响应正文
-
状态行:协议状态代码描叙(Protocol-Status codeDescription)
-
消息报头(Response headers)
-
响应正文(Entity body)
HTTP响应
-
状态行:HTTP-Version Status-Code Reason-Phrase
-
HTTP-Version表示服务器HTTP协议的版本;
-
Status-Code表示服务器发回的响应状态代码
-
Reason-Phrase表示状态代码的文本描述。
-
-
状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:
-
1xx:指示信息–表示请求已接收,继续处理,范围是100~101
-
2xx:成功–表示请求已被成功接收、理解、接受,范围是200~206
-
3xx:重定向–要完成请求必须进行更进一步的操作,范围是300~305
-
4xx:客户端错误–请求有语法错误或请求无法实现,范围是400~415
-
5xx:服务器端错误–服务器未能实现合法的请求,范围是500~505
-
-
2、响应报头
-
3、响应正文就是服务器返回的资源的内容
HTTP常见响应状态码
-
200:客户端请求成功
-
302:重定向
-
404:请求的资源不存在
-
400:客户端请求有语法错误,不能被服务器所理解
-
401:请求未授权
-
403:服务器收到请求,但是拒绝提供服务
-
500:服务器内部错误
-
503:服务器当前不能处理客户端的请求,一段时间 后可能恢复正常
HTTP响应首部
- 服务器根据客户端发送的请求返回的内容
- Server:服务器所使用的Web服务器名称
- Set-Cookie:向客户端设置Cookie
- Last-Modified:服务器通过这个头信息告诉浏览器, 资源的最后修改时间
- Location:告诉浏览器去访问那个页面,浏览器接收 到这个请求后会立刻访问Location头所指向的页面
- Refresh:服务器通过Refresh头告诉浏览器定时刷新浏览器
常用认证绕过方法
- 修改get参数
- 修改post参数
- 修改cookie参数
- 等等
SQL注入
sql注入原理
SQL注入可描述为通过在用户可控参数中注入 SQL语法,从而破坏原有的SQL结构,达成攻击行为。
其原因可归纳如下:
- 程序编写者在处理程序和数据库交互时,使用字符串拼接的方式构造SQL语句
- 未对用户可控参数进行足够的过滤便将参数内容拼接进入 到SQL语句中
SQL注入类型分类
- 整型注入
select * from user where id = 1
- 字符串类型注入
select * from user where name = ‘admin’
常见sql注入位置
- GET方式注入
url中进行sql语句注入
- POST方式注入
表单、登录框中进行sql语句注入
- HTTP头部注入
http请求头中进行注入( X-Forwared-For / HOST 等)
- Cookie注入
利用cookie字段注入
常见注入手法
- UNION query SQL injection(联合查询注入)
- Error-based SQL injection(报错型注入)
- Boolean-based blind SQL injection(布尔型注入)
- Time-based blind SQL injection(基于时间延迟注入)
联合查询注入
UNION 必须由两条或两条以上的SELECT 语句组成, 语句之间用关键字UNION 分隔
UNION 中的每个查询必须包含相同的列
UNION 会从查询结果中自动去除重复行
利用前提: 页面上有显示位
优点: 方便、快捷、易于利用
缺点: 需要显示位
报错注入
SQL报错注入就是利用数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中。
MYSQL报错注入大体可以分为以下几类:
-
BIGINT等数据类型溢出
-
Xpath语法错误
-
concat+rand()+group_by()导致主键重复
-
数据库的一些特性
注意,在使用报错语句时,有两种使用方法,一种是AND连接, 报错语句不需要写SELECT;另一种是UNION,报错语句需要写SELECT,同时还要注意列数量要对应,推荐使用AND连接。
常用报错注入方式
- 利用 double 数值类型超出范围进行报错注入
union select (exp(~(select * from(select user())a))),2,3 --+
- 利用 bigint 溢出进行报错注入
union select(!(select * from (select user())x) - ~0)
- xpath 函数报错注入
extractvalue(1,concat(0x7e,(select @@version),0x7e))–+
updatexml(1,concat(0x7e,(select @@version),0x7e),1)–+
- 利用数据的重复性
union select 1,2,3 from (select name_const(version(),1),name_const(version(),1))x --+
布尔盲注
- 判断是否存在注入,注入是字符型还是数字型
例:1 or 1=1,1’ or '1’=‘1
- 猜解当前数据库名
例:猜长度 and length(database())=1 #
逐个猜字符and ascii(substr(databse(),1,1))>97#
- 猜解数据库中的表名
例:猜表数量 and (select count (table_name) from information_schema.tables where table_schema=database())=1 #
逐个猜表名长度and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1 #
再逐个猜表名字符 and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 #
-
猜解表中的字段名,
例:猜字段数量and (select count(column_name) from information_schema.columns where table_name= ’users’)=1 #,
逐个猜字段长度and length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=1 #,
再逐个猜字段字符(可用二分法)
-
猜解数据,先猜数据记录数(可用二分法),再逐个字段猜数据的长度及数据(可用二分法)
延时注入
-
1.判断是否存在注入,注入是字符型还是数字型,
例:and sleep(5) #
-
2.猜解当前数据库名
例:猜长度 and if(length(database())=1,sleep(5),1) #
逐个猜字符 and if(ascii(substr(database(),1,1))>97,sleep(5),1)
-
3.猜解数据库中的表名
例:猜表数量 and if((select count(table_name) from information_schema.tables where table_schema=database() )=1,sleep(5),1)#
逐个猜表名长度 and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1,sleep(5),1)
再逐个猜表名字符
-
4.猜解表中的字段名
例:猜字段数量 and if((select count(column_name) from information_schema.columns where table_name= ’users’)=1,sleep(5),1)#
逐个猜字段长度 and if(length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=1,sleep(5),1) #
再逐个猜字段字符(可用二分法)
-
5.猜解数据,先猜数据记录数(可用二分法),再逐个字段猜数据的长度及数据(可用二分法)
sqlmap注入工具
检测注入
- get型:?id=1
python sqlmap.py -u “http://xxxxxxxx/index.php?id=1”
- post型:-r / --date / --forms
BP抓包,将请求报文sent to file----aa.txt文件中
python sqlmap.py -r“路径/aa.txt”
- cookie型:–cookie
python sqlmap.py –u “http://xxxxxxxx/index.php” --cookie “id=1–level 共有 五个等级”–level 2
Level>=2时测试HTTP Cookie
Level>=3时测试HTTP User-Agent
Level=5时测试HTTP Host
Sqlmap access注入
- 检测注入点
sqlmap.py -u “url”
“-u”选项用于指定URL
- 猜解表名
sqlmap.py -u “url" –tables
–tables”选项用于指定猜解数据库中包含哪些表
- 猜解字段名
sqlmap.py -u “url” --columns -T "manage_user“
“-T”选项,指定对哪个表进行猜解
“–columns”选项,告诉sqlmap这次的任务是猜解字段名
- 爆出字段内容
sqlmap.py -u “url” --dump -C “username,password” -T "manage_user“
选项“–dump”连同选项“-C”一起使用,意为猜解指定字段中的内容
注入流程
- sqlmap.py -u “url” --tables -D "govcn “
- 爆出指定数据库的所有表
- sqlmap.py -u “url” --columns -T “admin” - D "govcn “
- 爆出指定表的列项
- sqlmap.py -u “url” -T “admin” -D "govcn "
- 输出指定数据库指定表的指定列的记录
MYSQL导出一句话
-
into outfile ‘path’
- 权限足够,一般是root
- 爆web绝对路径
- GPC魔法开关未开启
-
load_file()读取敏感信息
- 必须有权限读取并且文件必须完全可读
and (select count(*) from mysql.user)>0 返回正常,说明具有读写权限。
and (select count(*) from mysql.user)>0 返回错误,说明不具有读写权限。
- 欲读取文件必须在服务器上
- 必须指定文件完整的路径
- 欲读取文件必须小于 max_allowed_packet
绕WAF、安全狗技巧
-
WAF过滤机制:
- 异常检测协议–拒绝不符合HTTP标准的请求;
- 增强的输入验证–代理和服务端的验证而不只是限于客户端验证;
- 白名单&黑名单机制–白名单适用于稳定的Web应用,黑名单适合处理已知问题;
- 基于规则和基于异常的保护–基于规则更多的依赖黑名单机制基于,基于异常根据系统异常更为灵活;
- 另外还有会话保护、Cookies保护、抗入侵规避技术、 响应监视和信息泄露保护等。
-
大小写绕过
- 此类绕过不经常使用,原理是基于SQL语句不分大小写,但过滤只过滤了其中一种。
-
替换关键字
- 这种情况下大小写转化无法绕过而且正则表达式会替换或删除select、union这些关键字如果只匹配一次就很容易绕过
- SELselectECT 1,2,3,4
-
空格绕过
select/**/*/**/from/**/yz; select%0a*%0afrom%0ayz; -- %0a是回车 /*!select*//*!**//*!from*//*!yz*/; select(a)from(yz); select(a)from(yz)where(a=1);
-
URL编码
- 有时后台界面会再次URL解码所以这时可以利用二次编码解决问题
- 后台语句
$insert=$link->query(urldecode($_GET['id'])); $row=$insert->fetch_row();
- 绕过:
select * from yz select * from %2579%257a
-
十六进制绕过(引号绕过)
在SQL语句的数据区域可以采用十六进制绕过敏感词汇
select a from yz where b=0x32; select * from yz where b=char(0x32); select * from yz where b=char(0x67)+char(0x75)+char(0x65)+char(0x73)+char (0x74) select column_name from information_schema.tables where table_name="users" select column_name from information_schema.tables where table_name=0x7573657273
-
逗号绕过
在使用盲注的时候,需要使用到substr(),mid(),limit。 这些子句方法都需要使用到逗号。对于substr()和mid()这 两个方法可以使用from to的方式来解决。
mid(user() from 1 for 1)
substr(user() from 1 for 1)
select substr(user()from -1) from yz ;
select ascii(substr(user() from 1 for 1)) < 150;
同时也可以利用替换函数
select left(database(),2)>'tf';
- 比较符(<,>)绕过
同样是在使用盲注的时候,在使用二分查找的时候需要使用到比较操作符来进行查找。如果无法使用比较操作符, 那么就需要使用greatest,strcmp。
select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64
select strcmp(left(database(),1),0x32);#lpad('asd',2,0)
if(substr(id,1,1)in(0x41),1,3)
- 注释符绕过
在注入时的注释符一般为 # – 当两者不能用时就不能闭合引号
select 1,2,3 from yz where '1'/1=(1=1)/'1'='1'
(1=1)中就有了判断位为下面的注入打下基础
- 宽字节绕过
%df’
会被PHP转义(开启GPC、用addslashes函数,或者icov等),单引号被加上反斜杠/
,就变成了 %df/’
,其中/
的十六进制是 %5C
,那么现在 %df/’
= %df%5c%27
,如果程序的默认字符集是GBK等宽字节字符集,则MYSQL用GBK的编码时,会认为 %df%5c
是一个宽字符,也就是縗’
,也就是说:%df/’
= %df%5c%27
=縗’
,有了单引号就好注入了。
文件上传
CTF中的文件上传主要是利用常见的上传漏洞获取flag,不同于渗透攻防过程中的上传漏洞,CTF中的上传漏洞大部分都是基于代码方面的限制,对我们上传文件进行合理性检测,需要我们突破上传限制。
常见的文件上传检测类型:
- 前端JS检测
- 黑名单检测
- 白名单检测
- 内容检测
- 等等
客户端绕过
客户端javascript检测的概念:当客户端选中要上传的文件点击上传的时候,如果没有向 服务端发送任何数据信息,就是对本地文件进行检测是否 是允许上传的文件类型,这种方式称之为客户端本地 javascript检测
绕过方法为:修改JS代码,添加允许上传类型
黑名单绕过
当客户端将文件提交到服务端的时候,服务端根据自己设定的黑名单对客户端提交上来的文件扩展名进行判断,如果上传的文件扩展名是黑名单里面所限制的,则不予上传。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HcO8pLFv-1604453612556)(https://i.loli.net/2020/11/02/RShrULOGMNsvgYm.png)]
CTF中常见黑名单绕过方法:
- 特殊可解析后缀
- 上传.htaccess文件
- 大小写绕过
- 点跟空格绕过
- ::$DATA绕过
- 双后缀绕过
- 配合解析漏洞绕过
特殊可解析后缀
如果黑名单仅仅是对常见的文件后缀(例如php)进行限制,则可以上传其他特殊可解析的文件后缀进行绕过。(例如php3/php5等等)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FNJNxFQG-1604453612558)(https://i.loli.net/2020/11/02/FNIgcRKdzmH2L3O.png)]
上传.htaccess文件
通过.htaccess文件,可以实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、 配置默认文档等功能,还可以重新重新定义解析规则。
例如:将jpg后缀文件当做php文件解析
<FilesMatch "4.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
利用上传的.htaccess文件重新定义解析规则
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RpyH5kvu-1604453612559)(https://i.loli.net/2020/11/02/DPrFqEIyHowx98a.png)]
大小写绕过
如果黑名单规则过于简单,仅仅是对我们上传的文 件后缀名字符进行过滤,而没有区分大小,就可以 利用文件后缀大小写绕过(windows下)
点和空格绕过
利用windows系统下的特性。当上传文件后缀名后面存在点跟空格时,上传文件在被保存到windows系统下时,后面的点跟空格会默认被去掉,利用这个特点,可以绕过一些黑名单规则。
::$DATA绕过
php在window系统下时如果文件名+::$DATA
会把::$DATA
之后的数据当成文件流处理,不会检测后缀名,且保持::$DATA
之前的文件名。
双后缀绕过
如果存在一些规则,导致删除我们黑名单列表中的字符,这时就可以利用双重后缀绕过。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oNPw66ti-1604453612563)(https://i.loli.net/2020/11/02/iOFsebfgdnp248W.png)]
解析漏洞
一些常见的web中间件在解析上传的文件时, 由于设计的缺陷,会产生一些畸形的错误解析,我们可以利用这些解析漏洞来突破上传限制。
-
IIS6.0错误解析漏洞
- 目录解析
形式:www.xxx.com/xx.asp/xx.jpg
原理: 服务器默认会把.asp,.asa目录下的文件都解析成asp文件。
- 文件解析
形式:www.xxx.com/xx.asp;.jpg
原理:服务器默认不解析;号后面的内容,因此xx.asp;.jpg便被解析成asp文件了。
- 解析文件类型
IIS6.0 默认的可执行文件除了asp还包含这三种 :
/test.asa
/test.cer
/test.cdx
-
IIS7.0/7.5错误解析漏洞
形式:www.xxxx.com/UploadFiles/image/1.jpg/1.php
原理:IIS7.0/7.5的漏洞,都是由于php配置文件中,开启 了cgi.fix_pathinfo,所以当接收到/1.jpg/1.php(不存在)参数时,会将1.jpg当做php文件解析
- Nginx解析漏洞
与IIS7.5类似
- Apache解析漏洞
形式:www.xxxx.xxx.com/test.php.xxxxx
原理:Apache 解析文件的规则是从右到左开始判断解析, 如果后缀名为不可识别文件解析,就再往左判断。
白名单绕过
文件上传白名单:当客户端将文件提交到服务端的时候,服务端根据自己设定的白名单对客户端提交上来的文件扩展名进行判断,只允许扩展名为上传白名单内的文件。
常见白名单列表绕过:
-
Content-type类型
-
%00截断、0x00截断
-
配合解析漏洞绕过
-
等等
Content-type类型绕过
MIME类型检测的概念:所谓MIME类型检测实际上就是客户端在上传文件到服务端 的时候,服务端对客户端上传的文件的Content-Type类型 进行检测,如果是白名单所允许的,则可以正常上传,否则上传失败。
-
常见的媒体格式类型如下:
-
text/html : HTML格式
-
text/plain :纯文本格式
-
text/xml : XML格式
-
image/gif :gif图片格式
-
image/jpeg :jpg图片格式
-
image/png:png图片格式
以application开头的媒体格式类型:
-
application/xhtml+xml :XHTML格式
-
application/xml : XML数据格式
-
application/atom+xml :Atom XML聚合格式
-
application/json : JSON数据格式
-
application/pdf :pdf格式
-
application/msword : Word文档格式
-
application/octet-stream : 二进制流数据(如常见的文件下载)
-
application/x-www-form-urlencoded : 中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
另外一种常见的媒体格式是上传文件之时使用的:
-
multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式
-
绕过方法:抓包修改content-type类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YUTRC2hM-1604453612564)(https://i.loli.net/2020/11/02/slu4aVZtXiAOHbq.png)]
截断上传绕过
截断的核心在于chr()这个函数,这个函数表示返回以数值表达式值为编码的字符,举个例子,print chr (78)
结果是N
,所以chr(0)
表示的ascii字符是 null
,当程序输出包含chr(0)
变量时,chr(0)
后面的数据会被截断,后面的数据直接忽略,导致漏洞产生。
%00
与0x00
两者原理都一样,都是ascii为0的字符,只是形式不同而已。
![image-20201102212257126](https://i.loli.net/2020/11/02/jRfy3hmV4baQoBw.png
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bvfBYBav-1604453612565)(https://i.loli.net/2020/11/02/4Gi1X2TVAnJjqwP.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VqOARhvZ-1604453612566)(https://i.loli.net/2020/11/02/IVtdoglWnecP6XA.png)]
条件竞争
条件竞争漏洞是一种服务器端的漏洞,由于服务器端在处理不同用户的请求时是并发进行的,因此如果并发处理不当或相关操作逻辑顺序设计的不合理时,将会导致此类问题的发生。
- 突破上传重命名
- 突破上传文件删除
上传漏洞防御
常见几种上传漏洞的防御方法:
- 检查文件上传路径 ( 避免 0x00 截断、 IIS6.0 文件夹解析漏洞、目录遍历 )
- 文件扩展名检测 ( 避免服务器以非图片的文件格式解析文件 )
- 文件 MIME验证 ( 比如 GIF 图片 MIME为 image/gif,CSS 文件的 MIME为 text/css 等 )
- 文件内容检测 ( 避免图片中插入 webshell)
- 图片二次渲染 ( 最变态的上传漏洞防御方式 , 基本上完全避免了文件上传漏洞 )
- 文件重命名 ( 如随机字符串或时间戳等方式 , 防止攻击者得到 webshell 的路径 )
- 另外值得注意的是, 攻击者上传了webshell之后需要得到webshell 的路径才能通过工具连接 webshell, 所以尽量不要在任何地方 ( 如下载链接等 ) 暴露文件上传后的地址。例如:有些网站的上传点在上传了文件之后不会在网页上或下载链接中暴露文件的相对路径, 但是在服务器返回的数据包里却带有文件上传后的路径。
文件包含漏洞
程序开发人员通常会把可重复使用的函数写到单个文件中, 在使用某个函数时,直接调用此文件,无需再次编写,这种调用文件的过程一般被称为包含。程序开发人员都希望代码更加灵活,所以通常会将包含的文件设置为变量,用来进行动态调用,但正是由于这种灵活性,从而导致客户端可以调用任意文件,造成文件包含漏洞。几乎所有的脚本语言都会提供文件包含功能。文件包含漏洞在PHP Web Application中居多,在JSP、ASP、ASP.NET程序中比较少。
原理: 程序在进行文件包含操作时,由于对要包含的这个文件来源过滤不严(用户可控),导致客户端可以 通过传递参数的形式将恶意文件包含进去,因此造成了文件包含漏洞,造成敏感文件泄露或者恶意代码注入等。
文件包含函数&文件包含分类
-
require()
require 找不到被包含的文件会产生致命错误,并停止脚本。
-
include()
找不到被包含的文件时只会产生警告,脚本将继续执行。
-
require_once()
与require类似,区别在于如果该文件中的代码已经被包含, 则不会再次包含
-
include_once()
与include类似,区别在于如果该文件中的代码已经被包含, 则不会再次包含
根据被包含文件位置的不同可以分为两类:
- 本地文件包含(LFI)
被包含文件在服务器本地上
- 远程文件包含(RFI)
被包含的文件在第三方服务器上
需要php.ini开启allow_url_fopen(默认开启)和 allow_url_include(默认关闭)选项
文件包含漏洞利用有很多,CTF中常常利用以下几种方式:
- 读取敏感文件
- 利用php伪协议读取php源码
- 配合上传漏洞getshell
- 等等
LFI敏感文件读取
- 分析代码
- 查看页面源码,获取信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ChWAzlBH-1604453612568)(https://i.loli.net/2020/11/02/GLBvrpKstQ3PoMV.png)]
- 进行LFI本地文件包含,获取flag
PHP伪协议利用
常见的php伪协议还有以下多种:
- file:// — 访问本地文件系统
- http:// — 访问 HTTP(s) 网址
- ftp:// — 访问 FTP(s) URLs
- php:// — 访问各个输入/输出流(I/O streams)
- zlib:// — 压缩流
- data:// — 数据(RFC 2397)
- glob:// — 查找匹配的文件路径模式
- phar:// — PHP 归档
- ssh2:// — Secure Shell 2
- rar:// — RAR
- ogg:// — 音频流
- expect:// — 处理交互式的流
在攻防中常常利用一些php的伪协议进行命令执行或 者包含shell文件,但是在CTF-web中,常常利用 php伪协议来进行源码的读取,然后进行代码审计, 获取解题思路,常用的php伪协议读取源码的方式有 以下几种:
- php://filter
用法:php://filter/read=convert.base64-encode/resource=[文件路径]
- php://input
allow_url_include选项必须设置为on,否则无法成功,此时 allow_url_fopen是否开启无关紧要。
php://input是用来接收post数据的
典型:file_get_contents()函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kdgzYtyo-1604453612570)(https://i.loli.net/2020/11/02/2CQ3OKhmuW1bE6d.png)]
- php://data
使用data://的时候allow_url_fopen和allow_url_include必须 都设置为on,否则利用就会失败
用法:data:text/plain,[php攻击代码] data:text/plain;base64,[攻击代码的base64编码]
PHP代码审计
md5碰撞
实例:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mpqq8huU-1604453612572)(https://i.loli.net/2020/11/02/M7xXJAgvBWlV5ab.png)]
原理:PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。
php弱类型判断
实例:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DH1IsuPY-1604453612573)(https://i.loli.net/2020/11/02/EJIYnk7RUFNOqil.png)]
利用了php中sha1()函数的漏洞,如果把这两个字段构造为数组, 如:?name[]=a&password[]=b,这样在第一处判断时两数组确实是不同的,但在第二处判断时由于sha1()函数无法处理数组类型,将报错并返回false,if 条件成立,获得flag。Md5()有同样的漏洞
Strcmp数组绕过
实例:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bPZhwrOC-1604453612574)(https://i.loli.net/2020/11/02/br7QemJP324VIZU.png)]
Strcmp()是二进制字符比较的安全函数。php5.3.3以后,当比较数组和字符串的时候,返回是0。
===
是恒等计算符 同时检查表达式的值与类型
==
是比较运算符号 不会检查条件式的表达式的类型
科学计数法
实例:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ihWqiwZM-1604453612575)(https://i.loli.net/2020/11/02/4wKNMjSO6cTRAbC.png)]
可以使用科学计数法,即1e3=1*10*10*10=1000>999
Ereg()函数
实例:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MD99iQvG-1604453612576)(https://i.loli.net/2020/11/03/EiuqkHZKUxFGjSN.png)]
可以利用ereg函数的%00截断。必须get输入,post表单不会把它当做截断符号。
变量覆盖
extract 可以将$_GET数组的值转为变量,默认是如果有冲突,则覆盖已有的变量。 File_get_contents()可以利用php://input绕过。
实例:
serialize() &unserialize()
serialize() 函数用于序列化对象或数组,并返回一个字符串。
unserialize() 对单一的已序列化的变量进行操作, 将其转换回PHP的值。
实例:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N5GR9rTI-1604453612578)(https://i.loli.net/2020/11/03/irVO4IbWLco2N1e.png)]
当$v->secret === $v->enter
的时候,输出flag值, 因为$v->secret
在输入反序列化之后,被重新赋值 了,如果让上述表达式成立?考察的是php中对象的比较,只要不是clone,那么就可以通过地址引用变量 a=&b
的形式,所以构造:因为序列化是可以序列化对象的,那么把$v->enter
赋值成$v->secret
的引用,就解决