关于注释
--
表示 SQL 标准注释,用于注释单行(注意最后有一空格)。
当网站存在尾部空格过滤的功能时,将会无法正确进行 SQL 注入
例如:
1 | SELECT * FROM users WHERE username='a' or true --' AND password='1' |
此处注入语句尾部空格被去掉,无法正常注入。
可用 MySQL 的单行注释符 #
来代替,不需要额外添加空格,更加简单有效。
也可在 --
后加上使尾部空格不会被过滤的其他字符,如 -- a
,有用但不推荐。
#
表示 MySQL 单行注释符,功能与 --
相同。
未编码的 #
在URL中被称为片段标识符( Fragment Identifier ),方便浏览器将页面滚动到对应内容的位置。浏览器不会将 #
后的内容发送到服务器,所以,如果要在导航栏中进行 SQL 注入并使用 #
,需要编码为 %23
。
我的第一道命令执行
题目: ctf.show web21
1 |
|
正则表达式会匹配 flag
,忽略大小写。如果 GET 请求的参数 c
中含有 flag
,便无法利用 eval
执行命令。
对此,先用 ls
命令看看目录里有什么:
1 | ?c=system(ls); |
tips
system()
函数:可执行操作系统命令,实时输出结果到浏览器/终端。此处
ls
命令无空格,所以可以不加引号,但依旧建议使用system()
函数时给命令加上引号。我的浏览器会自动 URL 转码,所以此处没转码。
目录中有两个文件: index.php
和 flag.php
,此时可以通过多种方式得到 flag.php
的内容:
方法一:
1 | ?c=system('cat fl*g.php'); |
通过通配符 *
绕过正则表达式,直接查看文件内容。但文件开头有个 <?php
,其中 <
会导致 HTML 解析异常,文件内容不会直接显示在网页中,要查看源码才能看到。
对此,作出如下改进:
1 | ?c=system('tac fl*g.php'); |
tac
命令从末行开始输出,最后输出首行,虽然 <?php
无法正常在网页中显示,但其他行全部正常显示。
方法二:
1 | ?c=system('cp fl*g.php a.txt'); |
通过 cp
命令复制一个新的文件 a.txt
,然后尝试通过 URL 访问该文件,成功。
方法三:
1 | ?c=echo file_get_contents($_GET[a]);&a=flag.php |
代码只过滤了 GET 请求的参数 c
,未过滤其它参数,所以此处设定参数 a
为 flag.php
然后再读取 $_GET[a]
能够绕过过滤。不过,同方法一的问题,文件内容在源码里,要开 F12 。
提醒一下自己,URL 传参没必要给每个参数的值加引号。
操作系统交互函数
system()
输出行为:直接输出命令的标准输出(STDOUT),输出所有结果。
返回值:成功时返回所有输出;失败时返回false
。
状态码:可通过第二个参数获取命令的退出状态码。
1 | $last_line = system('ls -la', $status_code); |
exec()
输出行为:默认不直接输出结果,需通过第二个参数捕获完整输出数组。
返回值:成功时返回命令的最后一行输出(若要全部输出,需要第二个参数捕获完整输出数组,然后输出该数组);失败时返回false
。
状态码:通过第三个参数获取退出状态码。
1 | exec('ls -la', $output, $status_code); |
shell_exec()
和反引号运算符(`)输出行为:不直接输出结果,返回完整输出字符串。
返回值:成功时返回完整的输出字符串;失败或空输出时返回null
。
1 | $result = shell_exec('ls -la'); |
passthru()
输出行为:直接输出原始二进制数据(如图像、音频)到浏览器。
返回值:无输出内容,但可通过第二个参数获取状态码。
1 | passthru('cat image.jpg', $status_code); |
我的第一次爆破
题目: ctf.show web21
考察 HTTP Basic 认证协议与爆破
进入靶场后随意输入账号密码 admin
与 password
,抓包发现 Authorization
字段中有 Base64 编码 YWRtaW46cGFzc3dvcmQ
,转换得 admin:password
。
此处基于 HTTP Basic 认证协议 ,会拼接账号、冒号与密码为一个字符串,再转换为 Base64 编码,插入请求头的 Authorization
字段。
但不管本题具体是什么协议,得到了账号密码拼接方式即可进行爆破。
打开 Burp Suite 的 Intruder 模块,在 Authorization
字段中添加 Payload 。
只有一个 Payload ,所以选择 Sniper attack 。在 Payloads 具体内容中, Payload type 选 Custom iterator (自定义迭代); Payload configuration 中的 Position 1-3 分别设置账号、 :
和密码字典; Payload processing 加入 Base64 编码;取消 Payload encoding 的 URL 编码(因为此处 Payload 不在 URL 中)。
开始攻击,有 200
状态码出现,复制对应的 Payload 到请求头 Authorization
字段,响应中有 flag ,OK。
PHP 伪随机数
题目一
1 |
|
tips
mt_srand()
:播种函数。伪随机数,种子相同,通过mt_rand()
生成的一系列随机数必然相同。也就是两次播种的种子是同一个,这两次播种后每次用mt_rand()
生成的随机数都互相对应。如:
1 |
|
mt_rand()
:随机数函数。可以直接用,也可以设定最大与最小值(参数1和参数2)
本题找个 PHP 解释器生成一下伪随机数,然后通过 URL 发送 GET 请求即可。
题目二
1 |
|
本题随机数种子固定 hexdec(substr(md5($flag), 0,8))
,**$_GET['r']
与首次生成的随机数不等时会返回两数相减的值,相等且 $_COOKIE['token']
等于第二三次生成随机数之和**时会返回 flag 。
可以先把已生成的随机数得出来:?r=0
,记得去掉负号,于是返回 flag 的第一重条件满足了。
通过伪随机数得到种子比较困难,好在有大佬写了工具 php_mt_seed ,把源码编译完即可运行。
https://github.com/openwall/php_mt_seed
在源码目录中编译
1 | make |
运行,<seed>
为种子。
1 | time ./php_mt_seed <seed> |
运行后选择 PHP 7.0 以上版本(结合题目提供的操作系统版本信息得知)的种子,每个生成三次随机数待使用。
打开 burp 抓包。修改 URL 中参数 r
,并添加 Cookie: token=
,值为某种子第二三次随机数的和(要多试几次不同的种子)。
手动修改 Cookie 时,一定要注意 burp 内的报文格式!若是请求体为空,则最后有两行空行(请求空行和请求体),这点与一般认知(请求空行作为最后一行表示请求体为空)不同。
手动修改时没注意,好几次发包响应报文都是完全空白。建议在 Proxy 模块的 Intercept 页或 Repeater 模块这两处右方的 Inspector 区域修改。
最后以正确格式发包,得到有 flag 的响应,OK。
ctfshow_Web23哈希爆破不写脚本
1 |
|
tips
substr()
:切割字符串,参数2为开始切割位置(含该字符),参数3为切割长度。
intval()
:取整数。
highlight_file(__FILE__)
:访问该 PHP 文件时高亮显示源码。
md5()
函数输出哈希字符串,结合下面的if
语句的极端罕见条件,本题只能靠穷举碰运气得出正确的哈希值,才能返回 flag 。
先在 URL 用 GET 方法传参(参数随意),抓包,传到 burp 的 intruder 模块修改。利用 Payloads 中 Payload type 的 Custom iterator ,组合出大量不同的 Payload 并攻击。最后以响应的长度排序,与其他包长度不一样的就是碰对运气带有 flag 的。
信息收集小技巧
- 开F12看不了源码,可以URL前加
view-source:
,也可以用Ctrl + U
,也可以自己找浏览器相关工具。 robots.txt
一般网站都能看,可以看看有没有要用的信息。.phps
类型的文件用于网站开发时测试。当服务器配置为支持.phps
扩展名时,访问此类文件会直接在浏览器中显示 PHP 源代码的语法高亮版本,而不是执行代码。若在网站投入使用时未正确配置服务器,导致可访问.phps
文件(直接下载或在浏览器中高亮显示),可能存在源码暴露的风险。- 响应标头中的
x-powered-by:
可以查看 PHP 版本。