BUUCTF 刷题笔记——Web 0
BUUCTF 刷题笔记——Web 0
[HCTF 2018]WarmUp
启动靶机
- 只有一张大黄猥琐斜眼笑脸出现,查看图片发现图片储存在 SM.MS 图床上(这不重要)。
查看源码
- 然后,
F12
查看源码,界面如下,可以看到右侧代码框内有一行绿色的耀眼文字。应该是线索?
- 在浏览器地址栏后方加上
/source.php
就可以访问文件。至于为什么,先挖个坑。
- 回车后我们就会得到以下代码:
1 |
|
显然,接下来就要进行代码审计了,那么,什么是代码审计呢?
顾名思义就是检查源代码中的安全缺陷,检查程序源代码是否存在安全隐患,或者有编码不规范的地方,通过自动化工具或者人工审查的方式,对程序源代码逐条进行检查和分析,发现这些源代码缺陷引发的安全漏洞,并提供代码修订措施和建议。
—— 百度百科
代码审计
- 在一开始,我们不难注意到这里定义了一个白名单数组,我们可以访问一下,万一有线索呢~
1 | $whitelist = ["source"=>"source.php","hint"=>"hint.php"]; |
- 在浏览器地址栏把
source.php
改成hint.php
即可,然后可以看到一串字符,虽然不是答案,但是我们得到了一个线索,flag 在ffffllllaaaagggg
里面。
1 | flag not here, and flag in ffffllllaaaagggg |
- 返回继续看刚才的代码,最下方有一小块代码,先解决他。
1 | if (! empty($_REQUEST['file']) |
$_REQUEST['file']
不认识是什么,先称他为 ¥if 语句判断三个条件
- ¥非空(
! empty()
) - ¥是字符串(
is_string()
) - ¥通过
checkFile()
函数且返回true
(emmm::checkFile()
)
- ¥非空(
如果¥不满足三大条件程序就会输出这个图片(
echo
);而如果程序满足三大条件,程序就会include
他。不知道
include
干嘛用,但是可以打开这个链接 https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg ,发现这就是网页上显示的大黄猥琐斜眼笑脸,显然,¥现在不满足三大条件,而要让网页发生点别的,就得让¥满足,我们先从checkFile()
函数入手。现在我们分析这个函数
第一个代码块
1 | if (! isset($page) || !is_string($page)) { |
依然是 if语句 的判断:如果 $page
满足
- 不存在或值为NULL(! isset())
- 不是字符串(!is_string())
其中之一,则输出 "you can't see it"
并返回 false
。大问题,我们不能让他执行。
第二个代码块
1 | if (in_array($page, $whitelist)) { |
依然是 if语句 的判断:如果 $page
存在于 $whitelist
也就是一开始定义得白名单数组中,就返回 true
。这个可以让他执行。
第三个代码块
1 | $_page = mb_substr( |
这里给 $_page
赋了个什么值:
mb_substr()
函数负责获取部分字符串;
mb_strpos()
函数负责查找字符串在另一个字符串中首次出现的位置;
在 PHP
中,字符串后的 '.'
为并置运算符,表示连接两个字符串;
因此,mb_strpos
返回的是 $page
字符串中的字符 '?'
之前的所有字符串,又因为字符串末尾置了一个 '?'
,若原字符串中不含 '?'
则会返回原字符串。
第四个代码块
1 | if (in_array($_page, $whitelist)) { |
这里重复了第二个代码块的内容,但是这次判断的是 $_page
,若存在于白名单中则返回 true
。也可以让他执行。
第五个
1 | $_page = urldecode($page); |
urldecode()
函数负责解码 URL 编码的字符串,这里将解码后的代码赋给了 $_page
。
第六个代码块
1 | $_page = mb_substr( |
这里重复了第三个代码块的内容,但是这次截取的是 $_page
自己的内容。
最后一部分
1 | if (in_array($_page, $whitelist)) { |
程序再次检查修改后的 $_page
是否在白名单中,若在,则返回 true
。若不在,则输出 "you can't see it"
并且返回 false
。
也就是说,若要
checkFile()
函数返回true
,则必须控制$page
参数不为空且为字符串,然后在三次判断是否在白名单中的任意一次让他存在于白名单中即可。而此时,白名单中只有两个成员:source.php
和hint.php
。所以
$page
是什么呢?1
emmm::checkFile($_REQUEST['file'])
从这段代码可以看出,$page
就是 $_REQUEST['file']
,而 $_REQUEST
是用于收集HTML表单提交的数据,属于PHP的超级全局变量。总之,他负责接收名为 file
的变量并且进行一次解码。而我们需要做的,就是给 file
赋一个字符串,并且让 checkFile()
函数返回 true
。
- 那么
file
的内容需要有什么?
在之前我们尝试访问白名单文件时,得到了一个提示:flag in ffffllllaaaagggg
,而我们的最终目的,就是让这个参数被 include
进去。这里利用的其实就是 文件包含漏洞 ,通过 include
包含并打开 ffffllllaaaagggg
即可。因此给 file
赋的字符串必须为包含文件 ffffllllaaaagggg
的路径名。
接下来我们需要让 checkFile()
返回为 true
,由于必须包含 ffffllllaaaagggg
,因此第一个白名单判断肯定无法使用,而第二个 if语句可以。因为第二次判断之前,程序对字符串进行了截取,我们只需保证 ?
之前为白名单成员即可。
当然,也可以用第三个if语句,不过因为调用了
urldecode(page)
对连接进行了二次解码,因此后面需要用%253f
(‘?’ 的二次编码)代替白名单元素后面的?
。
因此,file
可以取值为:
1 | file=hint.php?ffffllllaaaagggg |
或者是:
1 | file=source.php?ffffllllaaaagggg |
但是,由于我们需要通过 include
打开文件,但是我们需要的文件并不一定在当前目录下,因此,如果打开失败,可在文件名前加 ../
用来转到上一层目录查找。比如:
1 | file=source.php?../ffffllllaaaagggg |
仍无法找到可自行增加 ../
继续向上层目录查找即可。
- 那么,怎么把参数传到网页呢?
通过在 url
后以 ?
引导来添加参数,而且不同参数可用 &
分隔。即可以在地址栏输入以下内容则传参成功:
1 | https://靶机地址?file=hint.php?ffffllllaaaagggg |
一般用 payload
来表示后面这段参数:file=hint.php?ffffllllaaaagggg
开始夺旗(Flag)
将刚才得到的 payload
输入到浏览器地址栏之后,记得加 ?
。可以看到浏览器显示空页面,因为文件并不在当前目录下,因此我们需要添加 ../
来继续查找,可能会需要多个。
在添加五个 ../
之后,终于得到了我们的 Flag
!
所以,最终的 payload
为:
1 | file=hint.php?../../../../../ffffllllaaaagggg |
或者:
1 | file=source.php?../../../../../ffffllllaaaagggg |
当然还有:
1 | file=source.php%253f../../../../../ffffllllaaaagggg |
自此,夺旗成功。
[极客大挑战 2019]EasySQL
启动靶机
- 进入一个黑客背景的登录界面,需要用户名和密码,界面做得挺好看,就是看不到
flag
。
查看源码
- 看不出什么东西,所以直接浏览器右键查看源码,源码如下
1 |
|
<style>
标签部分可以不看,他在html
中负责定义页面样式,对解题没有帮助。需要注意的是注意下面<body>
标签内,有一个占用很大部分的<form>
标签。<form>
用于创建表单,也就是说,我们的登录信息应该会通过这里传递。- 可以注意到,
<form>
标签内有两个参数,他们表示用GET
方法提交到check.php
页面。
1 | <form action="check.php" method="GET"> |
method
负责设置提交的方法,一共有两种方法:POST
方法 和 GET
方法。
POST
方法
- POST数据放在body(POST提交的数据则放在实体数据),POST请求数据不能被缓存下来
- POST请求参数不会被保存在浏览器历史或 web 服务器日志中。
- POST请求没有长度限制
GET
方法
- 通过GET提交数据,用户名和密码将明文出现在URL上,因为登录页面有可能被浏览器缓存,GET请求请提交的数据放置在HTTP请求协议头
- 或者其他人查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了,除此之外,使用GET提交数据还可能会造成Cross-site request forgery攻击,所以不安全
- GET请求有长度限制
- 在网页中测试输入用户名和密码分别为
1
和123
,可以在地址栏中看到我们提交的数据,并且可以发现,我们所在的页面就是check.php
。且参数名分别为username
和password
。
- 显然,接下来我们就需要使用
SQL注入
,那么,什么是SQL注入
呢?
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
—— 百度百科
SQL注入
- 在数据库查询的时候,一般会使用如下语句:
1 | select * from user where username='&username&'and password='&password&' |
where
用于规定选择的标准。
&username&
和 &password&
分别为用户传入的用户名和密码,如果能在数据库中查询到则返回真值并通过验证。因此,其实只需要让 username='&username&'and password='&password&'
语句为真即可。
- 如果我们在用户名处输入类似于
' or 1
这样的字符串,那么查询语句就会变成这个样子:
1 | select * from user where username='' or 1'and password='&password&' |
- 但是这里就会多出一个单引号,服务器将会报错,因此这里我们需要用到注释,用
#
将后面的代码注释掉,就能正确返回真值了。用户名改为' or 1#
于是我们得到如下代码:
1 | select * from user where username='' or 1#'and password='&password&' |
当然,也可以用类似的方法修改密码。
开始夺旗(Flag)
- 在用户名处输入
' or 1#
,由于密码不能为空,因此顺便输入一个密码。登录即可。
也可以直接修改
url
,但是空格需要使用+
表示。可以看到
'
和#
被自动替换为了转义码%27
和%23
,我们在输入时也可以直接使用转义码输入。
自此,夺旗成功。
[极客大挑战 2019]Havefun
启动靶机
打开进入如下页面,只有一只小猫在中间,戳它会有反应呢(这不重要)!除此之外,连个可以点的地方都没有~
查看源码
什么都看不到,所以还是直接查看源码吧。源码好长一段,大部分都是界面设计代码,但是主题代码里有一段瞩目的注释:
1
2
3
4
5
6
7<!--
$cat=$_GET['cat'];
echo $cat;
if($cat=='dog'){
echo 'Syc{cat_cat_cat_cat}';
}
-->$_GET
变量用于收集来自method="get"
的表单中的值。if
语句判断表单中$cat
变量是否与dog
相等,相等则输出Syc{cat_cat_cat_cat}
。虽然不懂有没有什么用,但可以试试看。
测试提示
在
url
后加上?cat=dog
,回车查看。貌似,答案出来了……
开始夺旗(Flag)
- 嗯对确实就是刚才得到的答案
自此,夺旗成功。
[ACTF2020 新生赛]Include
启动靶机
- 打开靶机,页面只有一行 tips ,并且指向一个链接。
分析页面
点击链接,跳转出的新页面仅有一行 Can you find out the flag? 且上述链接仅在 URL 后添加了
?file=flag.php
。根据 URL 的变化判断为文件包含漏洞,我们只需读取
flag.php
文件即可。
读取文件
查询资料得知,
php://filter
与包含函数结合时,php://filter
流会被当作php文件执行。php://filter
是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似readfile()
、file()
和file_get_contents()
, 在数据流内容读取之前没有机会应用其他过滤器。php://filter
目标使用以下的参数作为它路径的一部分。 复合过滤链能够在一个路径上指定。详细使用这些参数可以参考具体范例。名称 描述 resource=<要过滤的数据流>
这个参数是必须的。它指定了你要筛选过滤的数据流。 read=<读链的筛选列表>
该参数可选。可以设定一个或多个过滤器名称,以管道符(` write=<写链的筛选列表>
该参数可选。可以设定一个或多个过滤器名称,以管道符(` <;两个链的筛选列表>
任何没有以 read=
或write=
作前缀 的筛选器列表会视情况应用于读或写链。
—— PHP手册php://filter
需要加上读取代码,比如read=convert.base64-encode
,用base64
编码输出,不然会直接当做php代码执行,而无法查看源代码内容。综上,构造
Payload
:1
?file=php://filter/read=convert.base64-encode/resource=flag.php
开始夺旗(Flag)
将上述
Payload
加入URL中,得到如下base64
编码的字符:1
PD9waHAKZWNobyAiQ2FuIHlvdSBmaW5kIG91dCB0aGUgZmxhZz8iOwovL2ZsYWd7MGFkNTg1NDAtZDc0ZC00MWU4LWJkYjQtMDlmNmUxZTNiZjAxfQo=
将
base64
字符解密,得到源代码,其中包含Flag
:1
2
3<?php
echo "Can you find out the flag?";
//flag{0ad58540-d74d-41e8-bdb4-09f6e1e3bf01}自此,夺旗成功。