本文最后更新于 169 天前,其中的信息可能已经有所发展或是发生改变。
咱就是说,上次XCTF得甲流,这次二阳,真会挑时候啊,拢共做了一道半(签到没抢上🤭),属实是废了
Misc
ezPythonCheckin
- payload,正准备绕呢,学弟就秒了,真是简单粗暴啊
,怎么flag名字都不改的
print(open('/flag').read())
cipher
- Advanced EFS Data Recovery
,考验选手搜索能力(,不知道用户密码没关系,导入一个top100字典即可,或者查看powershell历史记录
Users\test\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
cd C:\users\test\Desktop\
.\test2
cd C:\Users\test\Documents
.\test2
ipconfig /all
ipconfig
ping 192.168.17.140
net user
net user john john@123 /add
net user john superman /add
net user mark superman /add
net user ronnie superman /add
net user judd superman /add
net user neil superman /add
net user
net user steve superman /add
- 正经做法,贴一个,方便后续观摩(
偷!
# https://lilachit.notion.site/Lilac-2024DubheCTF-wp-caa603fa40ba4699982a13ddf062906a#1b970b22b5e04cb98a5e02cb2f688a4a
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
with open('private.pem', 'rb') as key_file:
private_key = serialization.load_pem_private_key(key_file.read(), password=None)
with open('$EFS', 'rb') as EFS_file:
efs = EFS_file.read()
'''
typedef struct
{
DWORD AttributeLength;
DWORD State;
DWORD Version;
DWORD CryptoAPIVersion;
BYTE Checksum[16];
BYTE ChecksumDDF[16];
BYTE ChecksumDRF[16];
DWORD OffsetToDDF;
DWORD OffsetToDRF;
} MFT_RECORD_ATTRIBUTE_EFS_HEADER, * PMFT_RECORD_ATTRIBUTE_EFS_HEADER;
'''
OffsetToDDF = int.from_bytes(efs[0x40:0x44], byteorder='little')
print(f'OffsetToDDF: {hex(OffsetToDDF)}')
'''
typedef struct {
DWORD Count;
} MFT_RECORD_ATTRIBUTE_EFS_ARRAY_HEADER, * PMFT_RECORD_ATTRIBUTE_EFS_ARRAY_HEADER;
'''
Count = int.from_bytes(efs[OffsetToDDF:OffsetToDDF+4], byteorder='little')
print(f'Count: {Count}')
assert Count == 1, 'Count != 1 unsupported for now'
'''
typedef struct {
DWORD Length;
DWORD CredentialHeaderOffset;
DWORD FEKSize;
DWORD FEKOffset;
} MFT_RECORD_ATTRIBUTE_EFS_DATA_DECRYPTION_ENTRY_HEADER, * PMFT_RECORD_ATTRIBUTE_EFS_DATA_DECRYPTION_ENTRY_HEADER;
'''
entry_header = efs[OffsetToDDF+4:OffsetToDDF+4+16]
Length = int.from_bytes(entry_header[0:4], byteorder='little')
print(f'Length: {hex(Length)}')
CredentialHeaderOffset = int.from_bytes(entry_header[4:8], byteorder='little')
print(f'CredentialHeaderOffset: {hex(CredentialHeaderOffset)}')
FEKSize = int.from_bytes(entry_header[8:12], byteorder='little')
print(f'FEKSize: {FEKSize}')
FEKOffset = int.from_bytes(entry_header[12:16], byteorder='little') + OffsetToDDF + 4
print(f'FEKOffset: {hex(FEKOffset)}')
encrypted_fek = efs[FEKOffset:FEKOffset+FEKSize][::-1]
decrypted_fek = private_key.decrypt(encrypted_fek, padding=padding.PKCS1v15())
'''
typedef struct {
DWORD KeyLength;
DWORD Entropy;
ALG_ID Algorithm;
DWORD Reserved;
BYTE Key[1];
} EFS_FEK, * PEFS_FEK;
'''
KeyLength = int.from_bytes(decrypted_fek[0:4], byteorder='little')
print(f'KeyLength: {KeyLength}')
Algorithm = int.from_bytes(decrypted_fek[8:12], byteorder='little')
print(f'Algorithm: {hex(Algorithm)}')
key = decrypted_fek[16:16+KeyLength]
assert 16 + KeyLength == len(decrypted_fek)
def decrypt_block(data_block, fek_key, index, cluster_size):
iv = bytearray(b'\0' * 16)
offset = index * cluster_size
iv[0:8] = (int.from_bytes(iv[0:8], byteorder='big') + offset).to_bytes(8, byteorder='big')
iv[8:16] = (int.from_bytes(iv[8:16], byteorder='big') + offset).to_bytes(8, byteorder='big')
cipher = Cipher(algorithms.AES(fek_key), modes.CBC(bytes(iv)))
decryptor = cipher.decryptor()
return decryptor.update(data_block) + decryptor.finalize()
def decrypt_file(input_file_path, output_file_path, fek_key, cluster_size=4096):
with open(input_file_path, 'rb') as input_file, open(output_file_path, 'wb') as output_file:
index_block = 0
while True:
data_block = input_file.read(cluster_size)
if not data_block:
break
decrypted_data = decrypt_block(data_block, fek_key, index_block, cluster_size)
output_file.write(decrypted_data)
index_block += 1
decrypt_file('flag.jpg.enc', 'flag.jpg', key)
- 相关链接
https://tinyapps.org/docs/decrypt-efs-without-cert-backup.html
authenticated mess & unauthenticated less
- 流量包里得到一些明文信息
{
"log": {
"loglevel":"debug"
},
"inbounds": [
{
"port": 1080, // SOCKS 代理端口,在浏览器中需配置代理并指向这个端口
"listen": "127.0.0.1",
"protocol": "socks",
"settings": {
"udp": true
}
}
],
"outbounds": [
{
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "1.95.11.7", // 服务器地址,请修改为你自己的服务器 ip 或域名
"port": 40086, // 服务器端口
"users": [
{
"id": "f3a5cae3-6bd2-40d1-b13b-2cc3d87af2c7",
"security":"auto"
}
]
}
]
}
}
]
}
- 查了个dns:
p.sda1.dev
,一个图床,猜猜流量是个图
- 参考
22年强网杯谍影重重
写一下解流量的脚本:https://wkr.moe/ctf/822.html,要把对于时间的校验删掉proxy/vmess/aead/authid.go
package main
import (
"bytes"
"encoding/hex"
"fmt"
"github.com/v2fly/v2ray-core/v5/common"
"github.com/v2fly/v2ray-core/v5/common/protocol"
"github.com/v2fly/v2ray-core/v5/proxy/vmess"
. "github.com/v2fly/v2ray-core/v5/proxy/vmess/encoding"
"io"
)
func toAccount(a *vmess.Account) protocol.Account {
account, err := a.AsAccount()
common.Must(err)
return account
}
func main() {
user := &protocol.MemoryUser{
Level: 0,
Email: "",
}
account := &vmess.Account{
Id: "f3a5cae3-6bd2-40d1-b13b-2cc3d87af2c7",
AlterId: 0,
}
user.Account = toAccount(account)
userValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash)
userValidator.Add(user)
defer common.Close(userValidator)
sessionHistory := NewSessionHistory()
defer common.Close(sessionHistory)
server := NewServerSession(userValidator, sessionHistory)
requestHex := "b6a64e055daca4fd0846544957e32cdabd6fa5213912538bc0a1657b023de2066672b7434aca736e9fd343e61be4707c7d8cecf526b4faba3d2798755a0510cdd84fb395659798fe67827ff578fbe58674f1fb534477c1e249100b7d2742df1456b15c26dd1666805bf25a2e46ef169996a046f8c23856e51ea0cbb17007c26f45c488bd8a02b4c8dc304d887cd939c2caa65dc7394c980f2446f014a29e41fa1729cda99db16454873525f9fc05dbf738dd4f6c0a17164c57146e867ddaf830d4bf4b3eeed61766e1f4b1cd2cbc84838feaaf04c896544a877974b52fd7aceb08feb5cb98454c83636ffd7c0e7e34ef939841ad7ee710c04fc65ad7ab208d26b9026620b8bc0dd77ef21afdb6c5d4cdaec4bb61a9ae5d01785bb887"
requestBuffer, _ := hex.DecodeString(requestHex)
requestBufferReader := bytes.NewReader(requestBuffer)
requestHeader, err := server.DecodeRequestHeader(requestBufferReader)
if err != nil {
fmt.Println(err)
}
fmt.Println(requestHeader)
requestBody, err := server.DecodeRequestBody(requestHeader, requestBufferReader)
if err != nil {
fmt.Println(err)
}
fmt.Println(requestBody)
for {
requestBodyBuffer, err := requestBody.ReadMultiBuffer()
if err != nil {
if err == io.EOF {
break
} else {
fmt.Println(err)
}
}
fmt.Println(requestBodyBuffer.String())
}
}
// proxy/vmess/aead/authid.go
func (a *AuthIDDecoderHolder) Match(authID [16]byte) (interface{}, error) {
for _, v := range a.decoders {
t, z, _, d := v.dec.Decode(authID)
if z != crc32.ChecksumIEEE(d[:12]) {
continue
}
if t < 0 {
continue
}
// 为 false 即可
if math.Abs(math.Abs(float64(t))-float64(time.Now().Unix())) < 0 {
continue
}
if !a.filter.Check(authID[:]) {
return nil, ErrReplay
}
return v.ticket, nil
}
return nil, ErrNotFound
}
- 得到图片地址
GET /16/11c111ee40a928d5d751dd5869414093/__p0.png HTTP/1.1
Host: p.sda1.dev
User-Agent: curl/8.5.0
Accept: */*
- 搜了一下,pixiv上找到原图,图片url后那串数即为附加压缩包的密码:116921220,得到一个项目(通宵了一下,做到这儿脑子已经混了,探服务探了好一阵儿,再加上已经第二天8点多了,就摆烂了),
EDtunnel
,一个轻量的代理,使用了wrangler
,代理两次将其调试端口代理出来即可
- 再偷wm
{
"log": {
"loglevel": "debug"
},
"inbounds": [
{
"port": 1081,
"listen": "0.0.0.0",
"protocol": "socks",
"settings": {
"udp": true
}
}
],
"outbounds": [
{
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "172.20.0.2",
"port": 8787,
"users": [
{
"encryption": "none",
"id": "5e5e7b9a-a251-441b-a81b-9d5b8a8f9019"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"tlsSettings": {
"disableSystemRoot": false
},
"wsSettings": {
"headers": {
"Host": "172.20.0.2:8787"
},
"path": "/?ed=2048"
},
"xtlsSettings": {
"disableSystemRoot": false
}
}
}
]
}