ByteCTF2021 MISC部分 解题思路和复现

阅读量    157100 | 评论 1

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

来写写ByteCTF2021的misc部分的解题思路,有些是比赛的时候出的,有些带点脑洞是赛后复现的,总体来说质量还不错

 

HearingNotBelieving

音频题,看频谱图前半部分是二维码

手动补全即可

m4yB3_

后面音频听着像慢扫电视

继续手撸,纯体力活啦

故flag为:ByteCTF{m4yB3_U_kn0W_S57V}

 

BabyShark

看到baby,一开始试图全局搜索bytectf从而获得flag

结果找到一个这个,追踪进去发现是一个Kotlin的apk

导出后反编译失败,说没找到classes.dex

重新检查流量包的数据,发现多了数据WRTE…..

从而导致压缩包解析错误

从这,压缩包内的文件路径被WRTE块截断,从而不难看出wrte是24字节的冗余数据,手动剔除

手动删除完毕,再反编译

package com.bytectf.misc1;

import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.StrictMode;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import dalvik.system.DexClassLoader;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;

public class MainActivity extends AppCompatActivity {
    /* access modifiers changed from: protected */
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView((int) C0095R.layout.activity_main);
        if (Build.VERSION.SDK_INT > 9) {
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());
        }
        String decrypt = AesUtil.decrypt(getAESKey(getPBResp(), loadPBClass(getPBClass()).getMethods()[37]), "8939AA47D35006FB2B5FBDB9A810B25294B5D4D76E4204D33BA01F7B3F9D99B1");
    }

    public Class loadPBClass(String jarFilePath) {
        try {
            return new DexClassLoader(new File(jarFilePath).getAbsolutePath(), getDir("dex", 0).getAbsolutePath(), (String) null, getClassLoader()).loadClass("com.bytectf.misc1.KeyPB").getClasses()[0];
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public String getPBClass() {
        if (ActivityCompat.checkSelfPermission(this, "android.permission.READ_EXTERNAL_STORAGE") != 0) {
            ActivityCompat.requestPermissions(this, new String[]{"android.permission.READ_EXTERNAL_STORAGE"}, 1);
            return HttpUrl.FRAGMENT_ENCODE_SET;
        } else if (ActivityCompat.checkSelfPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE") != 0) {
            ActivityCompat.requestPermissions(this, new String[]{"android.permission.WRITE_EXTERNAL_STORAGE"}, 1);
            return HttpUrl.FRAGMENT_ENCODE_SET;
        } else if (Environment.getExternalStorageState().equals("mounted")) {
            return Environment.getExternalStorageDirectory().getAbsolutePath() + "/PBClass.dex";
        } else {
            return HttpUrl.FRAGMENT_ENCODE_SET;
        }
    }

    public long getAESKey(byte[] pb_bytes, Method parseFrom) {
        try {
            Object respObj = parseFrom.invoke((Object) null, new Object[]{pb_bytes});
            return ((Long) respObj.getClass().getMethod("getKey", new Class[0]).invoke(respObj, new Object[0])).longValue();
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
    }

    public byte[] getPBResp() {
        byte[] pb_res = new byte[0];
        try {
            return new OkHttpClient().newCall(new Request.Builder().url("http://192.168.2.247:5000/api").build()).execute().body().bytes();
        } catch (IOException e) {
            e.printStackTrace();
            return pb_res;
        }
    }
}

主要是这里,其中getPBResp()中的api的结果可以从流量包中得到

然后难点就在于密钥生成的时候调用了getPBClass(),进而调用了PBClass.dex,这里的dex不能直接获取,但是要是换个思路,安卓下的PB,很容易想到ProtoBuf,想不到的话百度也不难搜到

而且,不难发现反编译得到的com.google包内就存在protobuf

那么就拿通过api得到的17字节的数据去解一下

显然1对应的就是符合long长度的key,去解一下

 

Lost Excel

excel文件,要溯源是谁泄露的,不难想到水印,先单独导出excel的水印图片后,发现0通道存在色点,但中间是有污染的

给了一个hint,提示说Block size = 8. Notice repeating patterns.

既然已经存在空域隐写了,再来频域转换可能性不大,故只考虑像素的规律

结合块大小为8,这里暂且先考虑是8*8的像素块,用ps分割一下看看

我们可以看到,刚巧每个8*8的像素块中最多有1个黑色块,且图中被红色框出的两块可以很明显的看出是重复的,所以其实我们只需使用上半部分即可,这样就可以避免掉原本中间被污染案的部分,再结合黑色像素块出现的位置(四种情况)可以对应转四进制,脚本如下

import cv2

img = cv2.imread(r'1.png')[:, :, 0]
h, w = img.shape
for j in range(0, h, 8):
    for i in range(0, w, 8):
        block = img[j:j + 8, i:i + 8]
        if block[0, 0] == 0:
            print(0, end='')
        elif block[0, 4] == 0:
            print(1, end='')
        elif block[4, 0] == 0:
            print(2, end='')
        elif block[4, 4] == 0:
            print(3, end='')
print('')

得到四进制,这里再转一下ascii

得到flag ByteCTF{ExcelHiddenWM}

 

frequently

拿到流量包,大致看看首先是dns的流量很奇怪

这个神似base64的域名不难想到有dns tunnel数据啊

还有一个io的也可以试试转01

这里先看看dns tunnel

值得注意的是流量中存在红色框中重复的,也有蓝色框中重复但id不同不能剔除的,故分别导出域名和id然后比对过滤

.\tshark.exe -r frequently.pcap -T fields -e dns.qry.name -Y “dns and ip.src==8.8.8.8 and frame.len!=91” > 0.txt

.\tshark.exe -r frequently.pcap -T fields -e dns.id -Y “dns and ip.src==8.8.8.8 and frame.len!=91” > 1.txt

然后结合起来剔除重复

dns = open(r'0.txt').read().splitlines()
id = open(r'1.txt').read().splitlines()
idli=[]
for i in range(len(dns)):
    if id[i] not in idli:
        idli.append(id[i])
        print(dns[i].split('.')[0],end='')
print('')

得到base64了,decode一下

很明显的png图片啊,导出看看

恶俗出题壬….搁这放诱捕器呢

再有io对应转10

这里可看到长度都是91且源ip都是8.8.8.8,以此过滤

.\tshark.exe -r frequently.pcap -T fields -e dns.qry.name -Y “dns and ip.src==8.8.8.8 and frame.len==91” > res.txt

oi对应转01

s = open(r'res.txt').read().splitlines()
for i in s:
    print(1, end='') if 'i' in i else print(0, end='')
print('')

010101000110100001100101001000000110011001101001011100100111001101110100001000000111000001100001011100100111010000100000011011110110011000100000011001100110110001100001011001110011101000100000010000100111100101110100011001010100001101010100010001100111101101011110010111110101111001100101011011100100101000110000011110010010011001111001001100000111010101110010

ok得到前半部分

然后继续,再去看看有什么流比较可疑

这里可以看到udp流有足足900+,且这里蓝色框中有一个内网ip向10.2.173.238发送过udp流,而10.2.173.238正是刚才发送dns解析的,故再来看看10.2.160.1

可以看到他发送了一堆dhcp报文

且报文的option字段还存在dns服务器是bytedance.net,十分可疑

进一步查看,他的租约期太短了吧,才几分钟

而且每次的租约时间都不同

故我们考虑获得dhcp.option.ip_address_lease_time字段(即租约时间)来看看

.\tshark.exe -r frequently.pcap -T fields -e dhcp.option.ip_address_lease_time -Y “ip.src==10.2.160.1” > res.txt

得到

115
115
101
49
102
95
119
73
116
104
95
109
49
115
99
94
95
94
125

简单转一下ascii

结合一下就行了

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多