2024 第八届 XCTF Final && 熊猫杯|Writeup

Cain's Dog

题目描述:

Cain's puppy is missing. He says it's a Samoyed that meows.Can u find him?

题目给了Cain's_dog.png、run.py和model.pth三个附件。
Cain's_dog.png:

其中run.py如下:

#!/usr/bin/python3
import sys
import numpy as np
from PIL import Image
import torch
import torch.nn as nn
from torchvision.models import resnet34
import base64
import io

model = resnet34()
model.fc = nn.Linear(model.fc.in_features, 2)
model.load_state_dict(torch.load('/model.pth', map_location='cpu'))
model.eval()

ori = np.array(Image.open("/Cain's_dog.png"))
base64_string = input("Could u help me find my dog?Please give me  the base64 of the dog image:\n")
image_bytes = base64.b64decode(base64_string)
buffered = io.BytesIO(image_bytes)
img = Image.open(buffered)
inp = np.array(img)

different_pixels_count = (ori != inp).sum()
if different_pixels_count > 100 :
    print('Not My Dog!!!')
    exit(0)

outputs = torch.tensor(inp.transpose(2, 0, 1) / 255.0, dtype=torch.float32).unsqueeze(0)
pred = torch.softmax(model(outputs), dim=1)

if pred[0][0] < 0.9:
    print("This dog doesn't meow~ , he's not my dog")
    exit(0)


print("Yes, my dog is about to become a cat girl! miao~")
print("flag{}")

思路就是单像素攻击,每次修改一个像素点。

# -*- coding: utf-8 -*-
# @Author  : 1cePeak

import torch
import torch.nn as nn
import numpy as np
from PIL import Image
from torchvision.models import resnet34
from torchvision.utils import save_image

def perturb(p, img):
    # Elements of p should be in range [0,1]
    img_size = img.size(1) # C x _H_ x W, assume H == W
    p_img = img.clone()
    xy = (p[0:2].copy() * img_size).astype(int)
    xy = np.clip(xy, 0, img_size-1)
    rgb = p[2:5].copy()
    rgb = np.clip(rgb, 0, 1)
    p_img[:,xy[0],xy[1]] = torch.from_numpy(rgb)
    return p_img

model = resnet34()
model.fc = nn.Linear(model.fc.in_features, 2)
model.load_state_dict(torch.load('./model.pth', map_location='cpu'))
model.eval()

ori = np.array(Image.open("./Cain's_dog.png"))

test_img = torch.tensor(ori.transpose(2, 0, 1) / 255.0, dtype=torch.float32).unsqueeze(0)

attack_img1 = perturb(np.array([3.58966099e-01, 6.56811724e-01, 5.87733625e-01, 1.13867609e-04, 2.97430753e-05]), test_img[0])
attack_img2 = perturb(np.array([0.34090759, 0.79827122, 1.     ,    0.    ,     0.21769902]), attack_img1)
attack_img3 = perturb(np.array([0.59172661, 0.63182162 ,0.06213244, 0.02224004 ,0.        ]), attack_img2)
attack_img4 = perturb(np.array([0.33929994 ,0.40123714 ,0.60364848 ,0.49595161, 0.        ]), attack_img3)
attack_img5 = perturb(np.array([0.26169169, 0.35602058, 0.   ,      0.47890641, 0.42390094]), attack_img4)
attack_img6 = perturb(np.array([0.29596823 ,0.79582006, 0.  ,       0.13034493, 0.10614204]), attack_img5)
attack_img7 = perturb(np.array([0.72041558 ,0.4443911,  0.79512668, 0.82490795, 0.35141815]), attack_img6)

pred = torch.softmax(model(attack_img7.reshape(1,3,224,224)), dim=1)
print(pred)

save_image(attack_img7,'./res.png')

再跑一下run.py检测脚本,看看能不能过检测。

#!/usr/bin/python3
import sys
import numpy as np
from PIL import Image
import torch
import torch.nn as nn
from torchvision.models import resnet34
import base64
import io

model = resnet34()
model.fc = nn.Linear(model.fc.in_features, 2)
model.load_state_dict(torch.load('./model.pth', map_location='cpu'))
model.eval()

ori = np.array(Image.open("./Cain's_dog.png"))
# base64_string = input("Could u help me find my dog?Please give me  the base64 of the dog image:\n")
# image_bytes = base64.b64decode(base64_string)
# buffered = io.BytesIO(image_bytes)
# img = Image.open(buffered)
# inp = np.array(img)
inp = np.array(Image.open("./res.png"))
different_pixels_count = (ori != inp).sum()
if different_pixels_count > 100 :
    print('Not My Dog!!!')
    exit(0)

outputs = torch.tensor(inp.transpose(2, 0, 1) / 255.0, dtype=torch.float32).unsqueeze(0)
pred = torch.softmax(model(outputs), dim=1)

if pred[0][0] < 0.9:
    print("This dog doesn't meow~ , he's not my dog")
    exit(0)


print("Yes, my dog is about to become a cat girl! miao~")
print("flag{}")

ICS2

题目描述

黑客对工控网络中的PLC设施了攻击,请你根据附件流量分析攻击行为并找到flag。
flag格式:flag{s7-300订货号后四位+CPU保护密码+M区偏移量10后三位的字符串值}

工控S7comm协议的流量,目前这一类题无非就是读写数据+脑洞编码。
先过滤s7comm协议。

右键追踪TCP流,发现订单号是6ES7 841-0CC05-0YA5

继续找s7comm协议读取CPU的数据包。根据用TIA Portal+S7Client暴力破解西门子S7-300/400密码的描述,S7-300用的是可逆加密算法,密码长度最多为8位,通过可逆算法转换成8个16进制数字通过S7协议发送给PLC。

int main()
{
    char opData[8],Pwd[8],pass[8];
    int c;
 
    opData[0] = '1';
    opData[1] = '2';
    opData[2] = '3';
    opData[3] = '4';
    opData[4] = '5';
    opData[5] = '6';
    opData[6] = 0x20;
    opData[7] = 0x20;
   
    Pwd[0] = opData[0] ^ 0x55;        
    Pwd[1] = opData[1] ^ 0x55;
    for (c = 2; c < 8; c++) {
         Pwd[c] = opData[c] ^ 0x55 ^ Pwd[c - 2];
    };

需要先在流量包中找到爆破密码的数据包。

找到编号1019的数据包,发现密码正确,提取请求包中的Data字段数据19253a012c602d66

逆向加密算法,解密CPU的保护密码

# -*- coding: utf-8 -*-
# @Author  : 1cePeak

def decrypt_pwd(Pwd):
    # 初始化 opData 数组
    opData = [0] * 8

    # 解密前两个字符
    opData[0] = Pwd[0] ^ 0x55
    opData[1] = Pwd[1] ^ 0x55

    # 解密剩余字符
    for c in range(2, 8):
        opData[c] = Pwd[c] ^ 0x55 ^ Pwd[c - 2]

    # 将数值转换为字符并形成字符串
    decrypted_opData = ''.join(chr(x) for x in opData)

    return decrypted_opData

encrypted_pwd = [0x19, 0x25, 0x3a, 0x01, 0x2c, 0x60, 0x2d, 0x66]
decrypted_opData = decrypt_pwd(encrypted_pwd)
print("Decrypted opData:", decrypted_opData)

# LpvqC4TS

解密出来的CPU密码是LpvqC4TS,那么还剩下最后一个M区偏移量10后三位的字符串值。
s7comm.param.item.area == 0x83过滤一下M区相关的数据包。

找到偏移量10区域的数据i#R

最终可以得到flag{0YA5+LpvqC4TS+i#R}

是谁偷偷偷走我的心

题目描述

N是一名大黑客,这天他盯上一个目标,发现这个目标里面一个秘密,N很感兴趣,于是掏出
大杀器偷走了目标上的机密数据,N发现目标系统利用自身系统中的信息对机密数据做了加密
保护的情况下仍然选择偷数据,但是不巧的是N的行为已经被记录在流量中了,现在需要对流
量进行分析定位查看,看看N想要偷走的数据是什么。
flag提交格式:最终长度为42位的flag{uuid}

太多了,思路就是先ntlm解密,然后再解密Winrm的流量,随缘更...

Bluetooth

题目给了一个xbox.pcapng的附件,猜测是XBOX手柄的流量。在解题之前不妨先看看XBOX手柄长啥样。

Macos打开流量包以后会报错,大概率尾部有脏数据,发现有一个ZIP压缩包,那肯定带密码了。那这道题的思路无非就是解密手柄的数据,解密压缩包拿到flag,实际结果也大抵如此。

看到l2cap协议有大量的通信,尝试过滤一下。

先过滤一下usb.src

发现数据量比较小,并且没有什么特殊含义,再过滤一下usb.dst

发现这次数据量就非常大了,用tshark全部提取出来分析一下。

tshark -r xbox.pcapng -Y "btl2cap.payload and usb.dst == host" -T fields -e btl2cap.payload > data.txt

得到的数据如下:

a10485
a1010b813c849f77a98c00000000000100
a1010b813c849f77a98c00000000000100
a1010b813c849f77a98c00000000000100
a1010b813c849f77a98c00000000000000
a1010b813c849f77a98c00000000000000
a1010b813c849f77a98c00000000000000
a1010b813c849f77a98c00000000010000
a1010b813c849f77a98c00000000010000
a1010b813c849f77a98c00000000010000
a1010b813c849f77a98c00000000000000
a1010b813c849f77a98c00000000000000
……
a1010b813c849f77a98c00000000030000
a1010b813c849f77a98c00000000000000
a1010b813c849f77a98c00000000000000
a1010b813c849f77a98c00000000000000
a1010b813c849f77a98c00000000030000
a1010b813c849f77a98c00000000030000
a1010b813c849f77a98c00000000030000
a1010b813c849f77a98c00000000000000
a1010b813c849f77a98c00000000000000
a1010b813c849f77a98c00000000000000

观察发现前14个字节重复出现,没有什么变化,可以删掉!

经过赛博算命发现最后一个重复出现的00字节也没啥用,删掉!

0001
0001
0001
0000
0000
0000
0100
0100
0100
0000
0000
0000
0100
0100
0100
0000
0000
0000
0300
0300
0300
0000
0000
0000
0300
0300
0300
0000
0000
0000
0300
0300
0300

继续观察剩下的数据,发现有同一个数据重复出现三次的情况,猜测是手柄按下和抬起的操作,那么继续把连续重复出现三次的数据只保留一次。精简后的所有数据如下:

0001
0000
0100
0000
0100
0000
0300
0000
0300
0000
0300
0000
0500
0000
0008
0000
0008
0000
0004
0000
0001
0000
0100
0000
0300
0000
0500
0000
0002
0000
0001
0000
0100
0000
0500
0000
0008
0000
0004
0000
0300
0000
0300
0000
0300
0000
0300
0000
0100
0000
0500
0000
0008
0000
0008
0000
0004
0000
0002
0000
0001
0000
0300
0000
0300
0000
0100
0000
0100
0000
0100
0000
0500
0000
0008
0000
0002
0000
0100
0000
0300
0000
0300
0000
0300
0000
0300
0000
0500
0000
0008
0000
0008
0000
0001
0000
0300
0000
0300
0000
0100
0000
0100
0000
0100
0000
0500
0000
0002
0000
0300
0000
0100
0000
0100
0000
0100
0000
0100
0000
0500
0000
0008
0000
0008
0000
0004
0000
0001
0000
0300
0000
0300
0000
0300
0000
0100
0000
0100
0000
0500
0000
0002
0000
0001
0000
0300
0000
0300
0000
0300
0000
0300
0000
0100
0000
0500
0000
0008
0000
0001
0000
0100
0000
0100
0000
0100
0000
0100
0000
0100
0000
0500
0000
0008
0000
0008
0000
0004
0000
0002
0000
0001
0000
0100
0000
0100
0000
0100
0000
0100
0000
0100
0000
0500
0000
0100
0000
0100
0000
0100
0000
0100
0000
0300
0000
0500
0000
0100
0000
0300
0000
0300
0000
0300
0000
0300
0000
0500
0000
0100
0000
0300
0000
0300
0000
0300
0000
0300
0000
0500
0000
0100
0000
0300
0000
0300
0000
0300
0000
0300
0000

接下来,继续对脑电波,根本对不上啊哥(
最终发现了规律:
第1个字节有三种情况

0x01
0x02
0x05

第2个字节有四种情况

0x01
0x02
0x04
0x08

那么这几种情况有什么含义呢?找到一篇分析的文章xbox-one-wireless-protocol,发现对不上,手头也没有XBOX手柄,那只能找游戏大师@seal师傅,让他抓一下XBOX的流量,发现还是对不上。

X:
Frame 87: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \\.\USBPcap2, id 0
USB URB
Bluetooth
Bluetooth HCI USB Transport
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
Bluetooth Attribute Protocol
    Opcode: Handle Value Notification (0x1b)
    Handle: 0x0007 (Unknown)
    Value: 0080ff7f0080ff7f0000000000080000

Y:
Frame 91: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \\.\USBPcap2, id 0
USB URB
Bluetooth
Bluetooth HCI USB Transport
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
Bluetooth Attribute Protocol
    Opcode: Handle Value Notification (0x1b)
    Handle: 0x0007 (Unknown)
    Value: 0080ff7f0080ff7f0000000000100000

A:
Frame 95: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \\.\USBPcap2, id 0
USB URB
Bluetooth
Bluetooth HCI USB Transport
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
Bluetooth Attribute Protocol
    Opcode: Handle Value Notification (0x1b)
    Handle: 0x0007 (Unknown)
    Value: 0080ff7f0080ff7f0000000000010000

B:
Frame 99: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \\.\USBPcap2, id 0
USB URB
Bluetooth
Bluetooth HCI USB Transport
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
Bluetooth Attribute Protocol
    Opcode: Handle Value Notification (0x1b)
    Handle: 0x0007 (Unknown)
    Value: 0080ff7f0080ff7f0000000000020000

上:
Frame 115: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \\.\USBPcap2, id 0
USB URB
Bluetooth
Bluetooth HCI USB Transport
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
Bluetooth Attribute Protocol
    Opcode: Handle Value Notification (0x1b)
    Handle: 0x0007 (Unknown)
    Value: 0080ff7f0080ff7f0000000001000000

下:
Frame 131: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \\.\USBPcap2, id 0
USB URB
Bluetooth
Bluetooth HCI USB Transport
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
Bluetooth Attribute Protocol
    Opcode: Handle Value Notification (0x1b)
    Handle: 0x0007 (Unknown)
    Value: 0080ff7f0080ff7f0000000005000000

左:
Frame 135: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \\.\USBPcap2, id 0
USB URB
Bluetooth
Bluetooth HCI USB Transport
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
Bluetooth Attribute Protocol
    Opcode: Handle Value Notification (0x1b)
    Handle: 0x0007 (Unknown)
    Value: 0080ff7f0080ff7f0000000007000000

右:
Frame 139: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \\.\USBPcap2, id 0
USB URB
Bluetooth
Bluetooth HCI USB Transport
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
Bluetooth Attribute Protocol
    Opcode: Handle Value Notification (0x1b)
    Handle: 0x0007 (Unknown)
    Value: 0080ff7f0080ff7f0000000003000000

rb:
Frame 31: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \\.\USBPcap2, id 0
USB URB
Bluetooth
Bluetooth HCI USB Transport
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
Bluetooth Attribute Protocol
    Opcode: Handle Value Notification (0x1b)
    Handle: 0x0007 (Unknown)
    Value: 0080ff7f0080ff7f0000000000800000

lb:
Frame 35: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \\.\USBPcap2, id 0
USB URB
Bluetooth
Bluetooth HCI USB Transport
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
Bluetooth Attribute Protocol
    Opcode: Handle Value Notification (0x1b)
    Handle: 0x0007 (Unknown)
    Value: 0080ff7f0080ff7f0000000000400000

左摇杆向右:前4个字节变化,猜测表示坐标
Frame 73: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \\.\USBPcap2, id 0
USB URB
Bluetooth
Bluetooth HCI USB Transport
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
Bluetooth Attribute Protocol
    Opcode: Handle Value Notification (0x1b)
    Handle: 0x0007 (Unknown)
    Value: 49 6a f4 82 0080ff7f0000000000000000

lt与rt存在多组数据,猜测与力度有关(油门)

但是第2个字节1、2、4、8四种情况很像四个按键LT、LB、RT、RB,找一下XBOX的按键分布图。

如果你做到这里会发现,你知道这些也没什么用,嘿嘿,还是得靠脑洞(
只看第二个字节这一列数据,第一个字节这一列数据作为分割符。

提取所有第二个字节的数据。

绿色是求和的部分,可以得到1,21,3,12,23,10,17,2,21,3,9,23,看到这里还得脑洞一下,对应26个英文字母。
其实这个是云影密码(又称01248密码)的原理,直接跑脚本也可以。

str = '0abcdefghijklmnopqrstuvwxyz'.upper()
for i in [1,21,3,12,23,10,17,2,21,3,9,23]:
    print(str[i],end='')

print()
# AUCLWJQBUCIW

得到的结果是AUCLWJQBUCIW,这个是压缩包的密码。

打开之后可以得到IfWT725Zkx/SSQdxoZPvm8ldX8BSrr1GU2h841iYrZbZL+rPPyjnboqduBPVO6cx,尝试解密失败。猜测是一个对称加密,那么还需要一个key,从何而来呢?
现在还有第一个字节的数据没有用到,0x01、0x02、0x05,脑洞一下morse编码,最终发现:

0x01,对应.
0x02,对应-
0x03,对应分隔符

可以得到

..--- .- . ----. --... .---- --... -.... ---.. ----. ..... ..... ....- .---- .---- .----

调用Cyberchef的morse模块解密一下得到2AE9717689554111

再调用AES模块解密一下

最终可以得到flag{5508d742-bae4-44a0-9376-25ba9c22de6d}

完结,撒花🎉