2024古剑山
2023古剑山
misc
数独(gaps拼图)
给了一个image.png和sudoku.png 先把数独解了一下 得到下面的结果
但是不知道有什么用 再看一下image.png 需要重新拼一下图 就用gaps就行了
原图像的大小是630x630 小图片是9x9 因此使用的size参数就是70
gaps --image=image.png --generations=50 --populations=200 --size=70 --save
这里我当时是以为数独有什么用 把解好的数独都写在原图片之后再拼的 实际上我们拼完之后直接按照从上到下 从左到右的顺序读flag就行
幸运饼干(DPAPI技术 Chrome数据加密)
附件是一个hint.jpg和flag.zip flag.zip里面有个和hint.jpg大小一样的文件 直接明文攻击 先将hint.jpg压缩为hint.zip 在ARCHPR里面进行明文攻击
得到密码
sv@1v3z
解压压缩包 得到一个压缩包 一个admin.txt和Cookie文件 先看一下Cookie文件格式 用file命令 是个sql数据库文件
admin.txt里面是使用mimikatz对计算机进行分析的记录 看到里面有一个NTML密码
解一下 密码是54231
先看一下前置知识
DPAPI,Data Protection Application Programming Interface,是Windows系统的一个数据保护接口,它本质上使用了Windows通过用户自己登录(sids,登录密码等),以及域登录后的一些数据生成的密钥,并且使用内置的算法,对用户指定的数据进行加密。通常Windows上的浏览器历史数据,邮件加密,wifi密码等等都会以这种方式进行数据加密。
Chrome使用DPAPI保存了我们的登录密码和cookie值
用户使用Chrome访问网站进行登录时,可以选择是否保存密码。当选择保存密码时,Chrome先将密码进行加密,再保存在SQLite数据库文件中,数据库文件路径位于:
%LocalAppData%\Google\Chrome\User Data\Default\Login Data
同上,保存Cookie时,数据库文件路径为:
%LocalAppData%\Google\Chrome\User Data\Default\Cookies
存储的cookie值被加密为DPAPI blob来进行保护;我们可以通过使用Mimikatz这个工具来对Chrome中的SQLite数据库进行解析:
mimikatz dpapi::chrome /in:'%LocalAppData%\Google\Chrome\User Data\Default\Cookies'
解密DPAPI blob用到的相关概念:
DPAPI blob:一段密文,可以使用Master Key对其解密
Master Key:64字节,用于解密DPAPI blob;使用用户登录密码、SID和16字节随机数加密后保存在Master Key file中
Master Key file:二进制文件,可以使用用户登录密码对其解密,得到Master Key
对采用DPAPI技术加密的数据进行解密,需要获取当前操作系统登录用户对应的 Master Key,而获取 MasterKey 需要知道用户名、密码以及对应的SID,然后利用这些数据生成一个 blob 加密过程中使用的 MasterKey,从而对目标blob进行解密
大致的过程是
dpapi::masterkey /in:{masterkeyfile} /sid:{sid} /password:{password} /protected
得到masterkey之后 使用masterkey(原key值或者sha1加密值都可以)解密Cookies/logindata
dpapi::chrome /in:{Cookies} /masterkey:{masterkey} /unprotect
这样就可以得到Cookies的加密数据的hex值或者直接得到明文
toto✌🏻的这篇文章写的很全面 狠狠膜拜了
电子取证中Chrome各版本解密Cookies、LoginData账号密码、历史记录
我们用sqlcipher打开Cooike这个sql数据库文件 看到有一个encrypted_value 提示是blob 那就是一个利用DPAPI技术加密的Chrome数据
我们结合前置知识 现在我们有了用户名 密码 在flag.zip解压后的文件里面还有一个压缩包 文件名就是SID 压缩包里面的文件应该就是masterkey文件
S-1-5-21-726299542-2485387390-1117163988-1001
有了这些我们就可以得到masterkey
dpapi::masterkey /in:.\S-1-5-21-726299542-2485387390-1117163988-1001\e5f8e386-7041-4f16-b02d-304c71040126 /sid:S-1-5-21-726299542-2485387390-1117163988-1001 /password:54231 /protected
这个地方遇到了几个问题 一是Cookies文件解压之后在文件夹里面是看不到的 但是用vscode打开文件夹作为工作区是可以看到的 二是注意一下最好是将文件夹或者Cookies文件直接放在mimikatz程序的文件夹中 放在其他位置有可能不出结果
下面就是用masterkey解密Cookies文件
dpapi::chrome /in:.\Cookies /masterkey:7a4d2ffbb42d0a1ab46f0351260aef16cae699e03e9d6514b3bf10e2977c5d228fda4a48e39b7b8a06a443c39653c2a3c3656596e7edc84e1c9682511c8343ac /unprotect
直接得到flag
另 在学习姿势的时候 还看到了一些将Cookies识别分割为数据库的方法
binwalk Cookies
dd if=Cookies bs=1 skip=0 of=1.db
同类型的题:[红明谷CTF 2022]MissingFile
我们再来看一下这道类似的题 主要是学习一下面对这种题的思路和解题步骤
附件是一个内存镜像文件memory
题目描述为
好像被攻击者入侵了,但是赶到现场的时候,已经只剩下一个空的文件夹了,快照能找到攻击者留下的秘密吗?
首先看一下被入侵的痕迹
.\volatility.exe -f E:\Desktop\比赛\古剑山\misc\[红明谷CTF2022]MissingFile\memory --profile=Win7SP1x86_23418 hashdump
可以看到有一个link3用户 还有一个NewGuest用户 既然是被入侵 那NewGuest应该就是攻击者入侵之后创建的账户
NewGuest用户的密码还是个可破解的哈希值 123456
再看一下攻击用户进行的文件操作 看到使用了mimikatz的记录
.\volatility.exe -f E:\Desktop\比赛\古剑山\misc\[红明谷CTF2022]MissingFile\memory --profile=Win7SP1x86_23418 filescan | findstr "NewGuest"
使用 mftparser 对内存中的 MFT 条目进行分析,并将结果保存至 mftparser.txt
MFT(Master File Table)是NTFS文件系统中的一个重要概念,它是用来存储文件和目录元数据的数据结构。MFT条目(MFT entry)是MFT中的一个记录,每个文件或目录在MFT中都有一个对应的MFT条目。
每个MFT条目包含了文件或目录的元数据信息,如文件名、文件大小、创建时间、修改时间等。MFT条目还包含了指向文件数据的指针,以及其他一些属性信息。
MFT条目的结构可以分为两部分:固定长度部分和可变长度部分。固定长度部分包含了MFT条目的基本信息,如文件类型、标志位等。可变长度部分则包含了文件属性信息,如文件名、时间戳等。
MFT条目在NTFS文件系统中起着非常重要的作用,它记录了文件和目录的元数据信息,使得文件系统能够有效地管理和访问文件。通过MFT条目,文件系统可以快速定位到文件的位置和属性信息,从而实现对文件的读取和操作。
.\volatility.exe -f E:\Desktop\比赛\古剑山\misc\[红明谷CTF2022]MissingFile\memory --profile=Win7SP1x86_23418 mftparser >mftparser.txt
在扫描文件的时候 找到了一个Hacker文件夹 我们在mftparser.txt里面继续找这个文件夹 找到了里面的S3cret
文件 将其进行保存
with open('S3cert.txt','r') as f:
data = f.readlines()
for line in data:
new_line = line[12:60:1]
print(new_line)
我们使用mimikatz检查一下S3cert
文件
privilege::debug
dpapi::blob /in:./S3cert
找到masterkey的guid 在mftparser.txt里面找一下这个guid
470a5148-d8c9-4453-bf41-f0c09d158bfd
找到了masterkey文件
一样 将这个masterkey文件导出来 命名为470a5148-d8c9-4453-bf41-f0c09d158bfd
下面就和幸运饼干的步骤一样了 先得到masterkey
dpapi::masterkey /in:.\470a5148-d8c9-4453-bf41-f0c09d158bfd /sid:S-1-5-21-206512979-2006505507-2644814589-1001 /password:123456 /protected
092c4220064c30bc7f8b15d2d48957c4926af0632149b9c08cd87f34fc43aa1204d775bdc6ab429a0d4d0826fb80b08250b125d92913e2f7578cf778073bfe38
在解密S3cert
文件
dpapi::blob /in:.\S3cert /masterkey:092c4220064c30bc7f8b15d2d48957c4926af0632149b9c08cd87f34fc43aa1204d775bdc6ab429a0d4d0826fb80b08250b125d92913e2f7578cf778073bfe38 /unprotect
得到16进制的明文
解一下
i_have_the_flag
附件是一个js文件还有一个html文件 看一下html文件
随便测试一下 发现输入不同错误内容的时候 回显的内容不一样 也不像base64编码 那就转向分析js文件 看到一段关键代码
function ck(s) {
try {
ic
} catch (e) {
return;
}
var a = [118, 108, 112, 115, 111, 104, 104, 103, 120, 52, 53, 54];
if (s.length == a.length) {
for (i = 0; i < s.length; i++) {
if (a[i] - s.charCodeAt(i) != 3)
return ic = false;
}
return ic = true;
}
return ic = false;
}
- 该函数的目的是检查输入字符串是否满足特定条件,即字符串的每个字符的 ASCII 值与数组中对应位置的数字相差 3。
- 如果满足条件,函数返回
true
,否则返回false
。
很简单 我们直接将上面数组a的ascii码全部减三 在解ascii码就可以得到正确的key了
simpleedu123
输入 就可以得到正确的值了 就是flag
jpginside
附件是jpginside.xxx
这样一个文件 不知道是什么类型的 用file命令看一下
是一个pyc文件 在线反编译一下
store = [
141,
183,
139,
129,
116,
117,
.....
49,
50]
key = raw_input('Please input the key:')
with open('excellent.jpg', 'wb') as jpg:
for i in range(len(store)):
jpg.write(chr(store[i] ^ ord(key[i % len(key)])))
先脚本恢复key 在上面的加密脚本里面用key加密的方式是对key的每一位循环使用 那我们只要取一部分明文和jpg图片格式里面相同的部分就可以恢复密钥 通过观察jpg图片结构 我们可以发现jpg的前13位都是一样的 那我们就选取这部分恢复我们的密钥
encrypted_data = [0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01]
# 已知的加密后的数据
store = [141, 183, 139, 129, 116, 117, 123, 116, 122, 114, 33, 115, 110]
# 恢复密钥的过程
key = ""
for i in range(len(store)):
original_byte = store[i] ^ encrypted_data[i]
key += chr(original_byte)
print("Recovered key:", key)
得到结果是
rotate1234!ro
那按照前面说的密钥是按位循环使用 我们就取前11位就是完整密钥
rotate1234!
有了密钥我们直接利用上面的加密脚本 得到exllcent.jpg
store = [
141,
183,
139,
129,
116,
117,
.....
49,
50]
key = rotate1234!
with open('excellent.jpg', 'wb') as jpg:
for i in range(len(store)):
jpg.write(chr(store[i] ^ ord(key[i % len(key)])))
注意这个脚本的运行欢迎是python2.7 python3运行可能会报错
得到图片
看文件结构发现尾部有一个压缩包
分离出来发现crc有问题 修改为504B
正常解压 需要密码 猜测是前面的key 得到jpek.txt
jpek{39i0jf49229fie5j33f02403hj953012}
随波逐流梭了
crypto
Vigenere+++
import sys
from secret_file import *
def _l(idx, s):
return s[idx:] + s[:idx]
def main(p, k1, k2):
s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_{}"
t = [[_l((i+j) % len(s), s) for j in range(len(s))] for i in range(len(s))]
i1 = 0
i2 = 0
c = ""
for a in p:
c += t[s.find(a)][s.find(k1[i1])][s.find(k2[i2])]
i1 = (i1 + 1) % len(k1)
i2 = (i2 + 1) % len(k2)
return c
flag="flag{************************}"
key="**********"
# * 为马赛克,长度为1。
# hint: 可以自己尝试下运行加密函数,看看秘钥对加密结果的影响。
# hint: 首先根据线索求秘钥,秘钥不唯一,找到一个有效的,就能爆破flag了。
print main(flag, key, key[::-1])
# 程序运行结果(即密文为):
kY0awfsdlY1FFL8C3bi4GSYCF{8W_E
比较无脑 ctfwiki原题
# exp2.py
enc_str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_{}'
dec_dic = {k:v for v,k in enumerate(enc_str)}
encrypt = 'kY0awfsdlY1FFL8C3bi4GSYCF{8W_E'
flag_bg = 'flag{**************************}'
sim_key = [dec_dic[encrypt[i]]-dec_dic[flag_bg[i]] for i in range(5)] # 破解模拟密钥
sim_key = sim_key + sim_key[::-1]
flag_ed = [dec_dic[v]-sim_key[k%10] for k,v in enumerate(encrypt)] # 模拟密钥解密
flag_ed = ''.join([enc_str[i%len(enc_str)] for i in flag_ed]) # 解码
print(flag_ed)
# flag{kynFTW2PRdH9lCZBf8IKDe6U}
guess_the_key
给了一个main.c 是加密函数的代码 给了msg01是明文 msg01.enc、msg02.enc是密文 先看加密代码
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
if (argc != 3) {
printf("USAGE: %s INPUT OUTPUT\n", argv[0]);
return 0;
}
FILE* input = fopen(argv[1], "rb");
FILE* output = fopen(argv[2], "wb");
if (!input || !output) {
printf("Error\n");
return 0;
}
char key[] = "guessthekey";
char d, q, t = 0;
int ijk = 0;
while ((q = fgetc(input)) != EOF) {
d = (q + (key[ijk % strlen( key )] ^ t) + ijk*ijk) & 0xff;
t = q;
ijk++;
fputc(d, output);
}
return 0;
}
其实关键的一步就是d = (q + (key[ijk % strlen( key )] ^ t) + ijk*ijk) & 0xff;
d是密文[i] q是明文[i] key是密钥[i] t在经历一次循环之后就是明文[i-1] ijk就是一个单独的参数 在每一次循环结束之后都自加1
由此我们利用明文msg.01和msg01.enc来破解出key
在这段加密代码中 key是每一位循环使用的 但对于前几位明文(不超过key的长度)来说 key[ijk % strlen( key ) 这一部分其实就是key[i]
我们可以利用爆破的方法 利用上面这个公式反推出q[i] = d[i] - key[i]^q[i-1] - pow(ijk, 2)
我们使用循环遍历每一位key[i]的值 当出现满足q[i] == text[i] (text是已知的明文)的key[i]时 我们就将这个key输出 下面是脚本
ciphertext = [0x9E,0x97,0x4B,0xD2,0x9A,0x8B,0xAD,0xA1,0x89,0x09,0xDE,0xAD,0x69,0x23,0x4E,0x76,0x70,0xAB,0xE4,0x97,0x44,0x22,0x81,0x8D,0x7F,0x22,0x23,0x70,0x7F,0xB5,0xFF,0x68,0x72,0xC1,0xC2,0x4B]
text = "Hi,there is nothing here,heiheihei."
t = 0
i = 0
for p in ciphertext:
for key in range(31, 125): # 这里表示的是key的ascii值
q = (p - (key ^ t) - i*i) & 0xff
q = chr(q) # 将q的ascii值转换为字符
try:
if q == text[i]:
print(chr(key), end="") # 将key的ascii值转换为字符输出
t = ord(q) # 将q的ascii值赋予t
i += 1
break
except:
print('')
# VeryVeryLongKeyYouWillNeverKnowVery
我们可以看到key出现了循环的部分 那么正确的key就是VeryVeryLongKeyYouWillNeverKnow
有了key 我们就可以继续写脚本获得msg02
msg02_enc = [0xA9,0x9F,0x83,0x45,0xEE,0x87,0x9B,0x6E,0x0E,0xC3,0xD4,0xE9,0xD5,0x61,0x36,0x81,0x70,0x96,0xD4,0xD7,0xF9,0xE4,0xC9,0x8C,0xD3,0xEA,0xDE,0xAC,0x7B,0xC5,0xA9,0x84,0x97,0xCB,0xB8,0xA8,0x8A,0x95,0x54,0x6D,0xBA,0xC0,0x7B,0xA0,0x06,0x68,0x9F,0x02,0xA8,0xCD,0x2A,0x52,0x49,0x91,0xE7,0x4A,0x71,0x6B,0xA8,0x1E,0x8E,0xBB,0xDC,0xED,0x7C,0x0B,0x5C,0x04,0x74,0x6B,0xBE,0x1C,0xC1,0x59,0xBC,0xAD,0x12,0xC2,0xFB,0xDA,0xEB,0x26,0xB1,0x61,0xED,0xE0,0x5D,0xF2,0xC8,0xA3,0x27,0xC5,0x96,0x58,0xAD,0xF5,0x8D,0x54,0x05,0xBC,0x47,0xAD,0x0C,0xE9,0xC0,0xAF,0x48,0x02,0x25,0x1E,0xC9,0xAB,0x6F,0x5B,0x37,0x30,0xBD,0x3A,0xC8,0xC7,0xCD,0xA0,0x4F,0xD9,0xBC,0x72,0x7E,0x84,0x53,0xB5,0x87,0x48,0xE5,0x8D,0x92,0xA9,0xC7,0xBC,0xEE,0x13,0x01,0xE7,0x5D,0x73,0x99,0x59,0x29,0xDC,0x1A,0xEF,0xA6,0xBB,0xB6,0xFD,0x12,0x86,0x82,0x7E,0x4C,0x6F,0x84,0xBA,0xF7,0x52,0x80,0x92,0x0D,0xB0,0xD9,0x07,0x40,0xF3,0x17,0x95,0xAF,0xC9,0xBB,0xE8,0xE7,0xF1,0x08,0x75,0xF4,0xF1,0x03,0x1C,0xC3,0x11,0x36,0x49,0xAA,0x04,0x69,0xF7,0xA0,0xC5,0xCD,0x17,0xC6,0x23,0x6B,0xBE,0xE7,0x7B,0xE2,0xE6,0x4B,0xD4,0x5E,0x55,0xC3,0x0C,0x54,0xD3,0x5C,0x05,0x79,0xCE,0x1B,0xD4,0x91,0x50,0xF6,0xB4,0x36,0x41,0x46,0xD5,0x38,0xB1,0x21,0xE0,0xE2,0x38,0xA2,0x65,0xB7,0x16,0x71,0xF7,0x82,0x56,0x4D,0x22,0xE2,0x3B,0xEE,0x89,0x1E,0xA7,0xB3,0x46,0xFA,0x82,0x83,0x3D,0xB1,0x8C,0x85,0x92,0xB7,0x52,0x99,0x13,0xBA,0x72,0x43,0xDB,0x10,0xE8,0xA0,0x5B,0x39,0xDA,0xB3,0xF8,0xF8,0xE3,0xAF,0xA2,0x6A,0x29,0x2F,0x82,0x91,0x6E,0x41,0x58,0x77,0xC8,0xAD,0xA8,0x89,0xCF,0x00,0xB3,0xB6,0x27,0x5F,0xC6,0xD6,0xAF,0xB3,0x1C,0x6B,0xF1,0x25,0xB8,0x20,0xA0,0xD1,0x89,0xBA,0x04,0xF9,0xD5,0x8E,0x0B,0xB0,0x10,0x8B,0x37,0x99,0xBC,0xBA,0x05,0xB3,0x58,0xA3,0x5C,0xF4,0x86,0x43,0xEA,0x08,0x1D,0x79,0xFE,0x1B,0x05]
key = 'VeryVeryLongKeyYouWillNeverKnow'
msg02 = ''
t = 0
for i in range(len(msg02_enc)):
if i ==0:
q = chr((msg02_enc[i] - (ord(key[i % len(key)]) ^ 0) - pow(i, 2)) & 0xff)
else:
q = chr((msg02_enc[i] - (ord(key[i % len(key)]) ^ ord(t)) - pow(i, 2)) & 0xff)
t = q
msg02 += q
print(msg02)
# She had been shopping with her Mom in Wal-Mart. She must have been 6 years old, this beautiful brown haired, freckle-faced image of innocence. It was pouring outside. The kind of rain that gushes over the top of rain gutters, so much in a hurry to hit the Earth, it has no time to flow down the spout.flag{101a6ec9f938885df0a44f20458d2eb4}
babyRSA
p=165183720742741436051373219716388644270093189046466421563632727622389425827620783096218651072108769567350808642169644915755493944233905573858905774991122631609402471527613272585988802294622263573574301013199411535656758222265554222107815469076608655188293263358371274025455477828555535371028164366376886408977
q=120848273460784230746197749214740170558670241437030497317956826606952430354830550737450520592481405802317202852411775956584677841602475259120706429378240071206662182089399302414435162197602907213282222144680788273948123482886712835590321726087823477518087588076504167863011019333002124841000448268076303735731
e=33
c=10407733127291995335613764691145477155502676597183852092212444772475748406250517097288411248334115120781386833588013995106957807313657632637086223225958539244315092039575434338289689184523710991223212333496000621300008178955253701172159259970353872359828291763446333588873982621853358272632447440961028670921631505593309092190417674648927653583956106734654954561031328286272044755552317084498103486458373580383410475085969677647030080606373264155592552338785789990114607084241499363324045488462563945268471178702696791804080490936763759252660049728533344304874474003893472238560682850602644793844258072019357796047919
上面就是我们能拿到的数据
看yolo师傅的博客学到是 有限域内开方 RSA中e和phi不互素问题
from Crypto.Util.number import *
p=165183720742741436051373219716388644270093189046466421563632727622389425827620783096218651072108769567350808642169644915755493944233905573858905774991122631609402471527613272585988802294622263573574301013199411535656758222265554222107815469076608655188293263358371274025455477828555535371028164366376886408977
q=120848273460784230746197749214740170558670241437030497317956826606952430354830550737450520592481405802317202852411775956584677841602475259120706429378240071206662182089399302414435162197602907213282222144680788273948123482886712835590321726087823477518087588076504167863011019333002124841000448268076303735731
e=33
c=10407733127291995335613764691145477155502676597183852092212444772475748406250517097288411248334115120781386833588013995106957807313657632637086223225958539244315092039575434338289689184523710991223212333496000621300008178955253701172159259970353872359828291763446333588873982621853358272632447440961028670921631505593309092190417674648927653583956106734654954561031328286272044755552317084498103486458373580383410475085969677647030080606373264155592552338785789990114607084241499363324045488462563945268471178702696791804080490936763759252660049728533344304874474003893472238560682850602644793844258072019357796047919
n = p*q
P.<a>=PolynomialRing(Zmod(p),implementation='NTL')
f=a^e-c
mps=f.monic().roots()
P.<a>=PolynomialRing(Zmod(q),implementation='NTL')
g=a^e-c
mqs=g.monic().roots()
flag=[]
for mpp in mps:
x=mpp[0]
for mqq in mqs:
y=mqq[0]
solution = CRT_list([int(x), int(y)], [p, q])
flag.append(solution)
for i in flag:
m=long_to_bytes(i)
if b'flag'in m:
print(m)