MISC-Write-Up-Zh

As a routine notepad to record some recurrent tasks in Chinese.

These tasks are somewhat special or interesting, which deserve recording.

[2022首届数据安全大赛]SQLPacket

SQLPacket.1

题干信息:

解题:

追踪的路径:

  • 协议分级,定位http
  • 查看对象,HTTP,发现存在cmd=ls等信息
  • 过滤数据,http contains "cmd=ls"
  • 右击过滤HTTP流
  • 发现secret1687456.txt

SQLPacket.2

题干信息:

解密:

  • url解码
  • base64解密

得到如下信息:

可得,密钥为05c1cc9c2deafb75,采用AES128加密。

到tq 197。

  • AES解密
  • base64解码

得到如下信息:

追踪HTTP流,使用返回包进行求解。

直接在notepad++中进行转换

  • base64解码
  • hex -> ascii 转换

从而得到secret1,即为ae1690a2-8e67-421e-bdcd-c4510995da98

[2022首届数据安全大赛]账密泄密追踪

账密泄密追踪.1

题干信息:

解题:

直接在GitHub上搜索green berry

进入项目中,使用泄露的五个账号依次查找,从而找到了泄露文件位置。

该url为https://github.com/Tristan-Hao/Green-Berry/blob/main/scrubbers.py

账密泄密追踪.2

题干信息:

解题:

因为在gitee平台,利用qingmei进行查找,发现该项目。

进入项目,进行查找。

该url为https://gitee.com/datasecurity-qunzhong/qing-mei-login/blob/master/scrubbers.py

账密泄密追踪.3

题干信息:

解题:

凡是还得登录以及必须手机号注册的东西,我告辞。

网上截图。

以及识别url后得到https://www.yuque.com/shuanxiaoming/gsx1eb/efnpu3

账密泄密追踪.4

题干信息:

解密:

得到泄露url,https://zhuanlan.zhihu.com/p/521587651

账密泄露追踪.5

题干信息:

解题:

在CSDN上,利用关键词青莓进行查找。

得到两个泄露url。

[2022首届数据安全大赛]泄露溯源定位

泄露溯源定位.1

题干信息:

解题:

这个流相对较大,再加上察觉到mysql的授权以及查看到后续存在隐私信息,所以基本定位该流为关键流。

所以定位该用户应该为dataUser3

泄露溯源定位.2

题干信息:

解题:

点进去得到网址:

https://github.com/Tristan-Hao/Green-Berry/blob/f766064e4f9c38bf4aefa06fd3d4abbda7fe4914/catalogue.py

所以提交即可。

泄露溯源定位.3

题干信息:

解题:

如果无法定位具体使用的数值是什么,那回归数据包进行查看。利用详情界面的值当作密文进行解密。

根据密文判断采用的解密类型,发现应当是AES,且密钥是aa01

根据解密之后得到的信息可以发现,除了姓名电话以外,还有地址银行账号以及邮箱地址也被泄露了,即ADE

[qwb2022]谍影重重

强网杯 2022 Writeup | GZTime’s Blog

2022年第六届“强网杯”网络安全大赛部分writeup (ehangwang.cn)

  • Route.pcapng
  • config.json
  • Amazing.zip

Amazing.zip为加密压缩包,加密文件为flag,基本判断通过其他两个文件得到压缩包的解压密码。打开压缩包也得到了明确的提示。

vmess协议

[协议细节 - VMess 协议 - 《Project V(V2RAY)文档手册》 - 书栈网 · BookStack](https://www.bookstack.cn/read/V2RAY/developer-protocols-vmess.md#VMess 协议)

v2fly/v2ray-core: A platform for building proxies to bypass network restrictions. (github.com)

主要就是看手册分析协议内容,根据协议定义进行计算。

时刻注意调用函数的格式,是字符串还是字节!本题基本都是字节。

协议初始定义

计算cmd_key以及cmd_iv

根据协议,先把指令部分求解出来。

我们的用户ID在config.json中体现。

1
2
3
4
5
6
7
"settings": {
"clients": [
{
"id": "b831381d-6324-4d53-ad4f-8cda48b30811"
}
]
}

使用匿名函数lambda把一些本题的常用函数给定义一下,简化调用步骤。

1
2
md5 = lambda x: hashlib.md5(x).hexdigest()
vmess_hmac = lambda x: hmac.new(client_id, x, hashlib.md5).hexdigest()

可以从协议定义来看,关键点在M之上。所以我们需要利用hmac值,爆破出关键的时间点M

但这一步莫名其妙一直没成功,无法爆出需要的时间,所以还有待改进中。不是python版本问题。

根据协议提示,写获取M的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 理论上
def get_cmd_iv(time, target_hash):
for t in range(time - 50, time + 50):
cur_hash = vmess_hmac(p64(t))
if cur_hash == target_hash:
print(f"time = {t}")
return md5(p64(t, endian='big') * 4)
# 硬凑版
def get_cmd_iv(time, target_hash):
for t in range(time - 50, time + 50):
cur_hash = vmess_hmac(p64(t))
# print(t)
# print(cur_hash)
if t == 1615528982:
print(f'time = {t}')
return md5(p64(t, endian='big') * 4)

p64()在pwntools库中,需要进行安装。

前置条件,需要找到进行响应的数据包基本条件:时间较早;数据量较大;存在数据。

大概的时间范围,以该流量包中的时间进行时间戳的转换。

找到参照时间戳为1615528962

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
import hmac
import uuid
from pwn import *

client_id = uuid.UUID('b831381d-6324-4d53-ad4f-8cda48b30811').bytes

md5 = lambda x: hashlib.md5(x).hexdigest()
vmess_hmac = lambda x: hmac.new(client_id, x, hashlib.md5).hexdigest()

req = bytes.fromhex('4dd11f9b04f2b562b9db539d939f1d52' + 'b48b35bf592c09b21545392f73f6cef91143786464578c1c361aa72f638cd0135f25343555f509aef6c74cd2a2b86ee0a9eb3b93a81a541def4763cc54f91ba02681add1b815e8c50e028c76bde0ee8a9593db88d901066305a51a9586a9e377ee100e7d4d33fcfc0453c86b1998a95275cd9368a68820c2a6a540b6386c146ea7579cfe87b2e459856772efdcf0e4c6ab0f11d018a15561cf409cbc00491d7f4d22b7c486a76a5f2f25fbef503551a0aeb90ad9dd246a9cc5e0d0c0b751eb7b54b0abbfef198b1c4e5e755077469c318f20f3e418af03540811ab5c1ea780c886ea2c903b458a26')
# print(req)
cut_time = 1615528962
target_hash = req[:16].hex()
# print(target_hash)

def get_cmd_iv(time, target_hash):
for t in range(time - 50, time + 50):
cur_hash = vmess_hmac(p64(t))
# print(t)
# print(cur_hash)
if t == 1615528982:
print(f'time = {t}')
return md5(p64(t, endian='big') * 4)

cmd_key = md5(client_id + b'c48619fe-8f02-49e0-b9e9-edf763e17e21')
cmd_iv = get_cmd_iv(cut_time, target_hash)
# print(type(cmd_iv))
# print(type(cmd_key))

print(f"cmd_key = {cmd_key}")
print(f"cmd_iv = {cmd_iv}")

# time = 1615528982
# cmd_key = "b50d916ac0cec067981af8e5f38a758f"
# cmd_iv = "881eb47d4d3b67b24328c5178c0eedcc"

对指令部分进行解密

根据协议手册,我们了解指令部分各字节的所属以及作用。需要注意的是,我们在此解密的数据是指令数据。

同样的,先利用匿名函数定义所要使用的AES-128-CFB

1
cmd_aes = lambda: AES.new(bytes.fromhex(cmd_key), AES.MODE_CFB, bytes.fromhex(cmd_iv), segment_size=128)

这边得高亮一下,python3中对称密码的使用非常麻烦,因为主要处理的数据都是字节形式,此处注意,不能直接使用b’’来进行转换,会导致长度错误,必须使用bytes.fromhex()进行转换。

AES-128的密钥长度必须为16字节,而b’’转换成字节是32字节,所以会导致报错。

校验F部分,使用FNV1a hash

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
from fnvhash import fnv1a_32
from Crypto.Cipher import AES
from Crypto.Util.number import *
cmd_aes = lambda: AES.new(bytes.fromhex(cmd_key), AES.MODE_CFB, bytes.fromhex(cmd_iv), segment_size=128)

cmd = req[16:]
ret = cmd_aes().decrypt(cmd)
print(f"ver = {ret[0:1].hex()}")
print(f"dat_iv = {ret[1:17].hex()}")
print(f"dat_key = {ret[17:33].hex()}")
print(f"v = {ret[33:34].hex()}")
print(f"opt = {ret[34]:b}")
print(f"p = {ret[35:36].hex()[0]}")
print(f"sec = {ret[35:36].hex()[1]}")
p = int(ret[35:36].hex()[0], 16)
print()
print(f"cmd = {ret[37:38].hex()}")
print(f"port = {bytes_to_long(ret[38:40])}")
print(f"type = {ret[40:41].hex()}") #ipv4
print()
print(f"host = {'.'.join(str(i) for i in ret[41:45])}")
print(f"rand = {ret[45:45 + p].hex()}")
print(f"F = 0x{ret[45 + p:45 + p + 4].hex()}")

print(f"check = {hex(fnv1a_32(ret[:45 + p]))}")

输出得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ver      = 01
dat_iv = 13277f5732da52ada790d87b8829daa9
dat_key = 5e4a9aa9ba58c7e3ad36fe2499dca259
v = a2
opt = 1101
p = 6
sec = 3

cmd = 01
port = 5000
type = 01

host = 127.0.0.1
rand = 1ace7d9bb0b5
F = 0x39182c03
check = 0x39182c03

根据协议协定信息进行解密

切分后得到的协议信息,比较关键的部分主要在dat_ivdat_keyopt以及sec中。

但通过文档发现Opt略显不对,主要因为文档年久失修:)

v2ray-core/headers.go at 5dffca84234a74da9e8174f1e0b0af3dfb2a58ce · v2ray/v2ray-core (github.com)

所以Opt部分,主要开启了GlobalPaddingChunkMasking以及ChunkStream,所以我们得到信息,元数据开启了数据混淆,所以我们客户端和服务端分别需要构造两个Shake实例。并且解密的时候注意Padding

sec部分,也不出意外的年久失修了:)

https://github.com/v2ray/v2ray-core/blob/5dffca84234a74da9e8174f1e0b0af3dfb2a58ce/common/protocol/headers.proto

sec=3的情况下,我们应该选择AES-128-GCM进行解密。

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
from Crypto.Hash import SHAKE128
# 协议初始定义中体现
class SizeParser:
def __init__(self, nonce):
self.shake = SHAKE128.new(nonce)

def next(self):
return bytes_to_long(self.shake.read(2))

def enc(self, size):
return self.next() ^ size

def dec(self, size):
return self.next() ^ size

def next_padding(self):
return self.next() % 64

print('------------------------------------------------')
def decrypt(arr, key, iv):
count = 0
parser = SizeParser(iv)
output = []
print(f"dat_iv = {key.hex()}")
print(f"dat_key = {iv.hex()}")
while len(arr) > 0:
padding = parser.next_padding()
L = parser.dec(bytes_to_long(arr[:2])) - padding

arr = arr[2:]
e_iv = p64(count, endian='big')[6:] + iv[2:12]

try:
dec = AES.new(key, AES.MODE_GCM, e_iv).decrypt_and_verify(arr[:L-16], arr[L-16:L])
output.append(dec)
except:
print('[!] Decryption failed!')
finally:
count += 1
arr = arr[L + padding:]
return output

data = cmd[45 + p + 4:]
data_iv = ret[1:17]
data_key = ret[17:33]
# print(type(data_key))
pprint(decrypt(data, data_key, data_iv)[0].decode().split('\r\n'))

得到输出:

1
2
3
4
5
6
7
8
9
dat_iv   = 5e4a9aa9ba58c7e3ad36fe2499dca259
dat_key = 13277f5732da52ada790d87b8829daa9
['GET /out HTTP/1.1',
'Host: 127.0.0.1:5000',
'User-Agent: curl/7.75.0',
'Accept: */*',
'Connection: close',
'',
'']

将所有响应数据进行解密

插播,前面都是请求数据,本部分为响应数据。

响应数据依旧使用AES-128-CFB进行解密。

响应数据我们如何得到?直接利用Wireshark追踪数据流功能进行查看。先转换成原始数据,再把所有蓝色数据导出即可。保存为res.bytes

依旧根据协议定义对解密后的数据进行切分提取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
res = open('res.bytes', 'rb').read()
# print(res)
res_key = md5(data_key)
res_iv = md5(data_iv)
# print(res_key)
# print(res_iv)
print(f"res_key = {res_key}")
print(f"res_iv = {res_iv}")
res_aes = lambda: AES.new(bytes.fromhex(res_key), AES.MODE_CFB, bytes.fromhex(res_iv), segment_size=128)
dec_res = res_aes().decrypt(res[:16])
print(f"v = {dec_res[0:1].hex()}")
print(f"opt = {dec_res[1:2].hex()}")
print(f"cmd = {dec_res[2:3].hex()}")
print(f"c_l = {dec_res[3:4].hex()}")
cmd_len = int(dec_res[3:4].hex(), 16)
print(f"cmd = {dec_res[4:4+cmd_len].hex()}")
data = res[4 + cmd_len:]
plaintext = decrypt(data, bytes.fromhex(res_key), bytes.fromhex(res_iv))

输出得到:

1
2
3
4
5
6
7
8
9
res_key  = b22984cda4143a919b5b6de8121b6159
res_iv = fa2a8ab0fadb4854943df690335a99b5
v = a2
opt = 00
cmd = 00
c_l = 00
cmd =
dat_iv = b22984cda4143a919b5b6de8121b6159
dat_key = fa2a8ab0fadb4854943df690335a99b5

解密之后所得文件

解密所得文件为一个 html 文件,其中以 base64 编码存放有一份宏病毒。因此这里取出其内容,实测电脑中的杀毒软件对此病毒十分敏感,一旦落入文件系统文件立刻会被损坏,最后为了查看内容直接存储为 zip 文件解压后查看。

1
2
3
4
5
6
7
8
9
from base64 import b64decode
data = ''.join(i.decode() for i in plaintext)
start = data.find("atob('") + len("atob('")
end = data.find("');", start)

binary = b64decode(data[start:end])
check_sum = hashlib.sha256(binary).hexdigest()

open('doc.zip', 'wb').write(binary)

这一步,如此如此这般这般就得到html文件,并且为宏病毒文件。暂且缘由不太理解,先放着。

利用病毒sha256值反向查找

把zip文件直接放foremost分析一下,能够得到病毒的dll。

1
2
$ sha256sum 00000277.dll
0d7aa23a72d22dcf47f8723c58d101b3b113cbc79dd407a6fac0e65d67076ea1 00000277.dll

检索得到:Malware analysis extracted_at_0x22a7b.exe Malicious activity | ANY.RUN - Malware Sandbox Online

得到api的urlhttp://api.ipify.org

md5得到压缩密码为08229f4052dde89671134f1784bed2d6

得到flag文件。

go文件

得到的文件使用WINHEX打开一下,发现提示了文件类型,是Gob文件

利用属性来进行定义,从而反序列化。

导包的时候出现了missing path,找了报错原因,没解决,后来发现是因为格式错了。

1
2
3
4
5
6
import (
"fmt"
"math/rand"
"time"
"os"
)

然后脚本的原理暂且还不太理解,先放着。

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
package main

import (
"math/rand"
"os"
"time"
)

func main() {
//seed init
loc, _ := time.LoadLocation("Local")
timeObj, _ := time.ParseInLocation(
"2006-01-02 15:04:05",
"2022-07-19 14:49:56", loc)
seed := timeObj.Unix()
rand.Seed(seed)

input, _ := os.Open("./src.png")
in := make([]byte, 70475)
lenx, _ := input.Read(in)
table := make([]int, lenx)
out := make([]byte, lenx)
for i := 0; i < lenx; i++ {
table[i] = i
}

//shuffle
rand.Shuffle(len(table), func(i, j int) {
table[i], table[j] = table[j], table[i]
})

for i := 0; i < lenx; i++ {
out[table[i]] = in[i]
}
output, _ := os.Create("./flag.png")
output.Write(out)

}

得到图片。

图片隐写

搞出一张图片了,但没明白为啥图片的大小就是70450bytes,有点迷惑。

没找到合适的工具提取隐写,十有八九是提取像素点的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from PIL import Image
import numpy as np
img = Image.open('flag.png')
arr = np.array(img)

ans = bytes(arr[:, :, 3].reshape(2000 * 973)).replace(b'\xff', b'').replace(b'\x00', b'').decode()[:42]
print(ans)
# flag{898161df-fabf-4757-82b6-ffe407c69475}

# from PIL import Image
# pic = Image.open('flag.png')
# w, h = pic.size
# flag = []
# for i in range(h):
# for j in range(w):
# piexl = list(pic.getpixel((j, i)))[3]
# if(piexl != 0xff):
# flag.append(chr(int(piexl)))
# if len(flag) == 42:
# print(''.join(flag))

最后得到flag{898161df-fabf-4757-82b6-ffe407c69475}

[qwb-2021]threebody

用图片讲一个故事——第五届强网杯Threebody题目官方题解-安全客 - 安全资讯平台 (anquanke.com)

stegsolve查看发现图片

你们都是虫子。

放大发现像素点数

相邻像素点数值相差较大。

仔细观察发现如果以4为周期相差像素点数值将相差不大。 -> 修改像素点所占比特数biBitCount 24 -> 32

得到真实图片。

再使用solvesolve进行分析

stegsolve进行提取。行列都存在隐写数据。

可得提示希尔伯特曲线

冗余数据赋值

观察图片发现存在rgbReserved的字段,表示stegsolve还存在无法识别的通道。

两种方法。

  • bmp转化成png
  • blue通道跟Reserved通道大小相近,直接暴力赋值

bmp转化成png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from PIL import Image
image=Image.new(mode='RGBA',size=(580,435))
with open(r'threebody.bmp','rb') as f:
file=f.read()
index=0
for i in range(434,-1,-1): #根据bmp的结构知道该bmp文件上下倒序存储像素值
for j in range(0,580):
s=[]
for t in range(0,4):
s.append(file[index])
index+=1
image.putpixel((j,i),(s[2],s[1],s[0],s[3])) #
image.show()
image.save('threebody_new.png')

暴力赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
with open('threebody.bmp', 'rb') as f:
d = f.read()

w = 580
h = 435
b = 4
l = bytearray(d)
off = l[10]
for i in range(h):
for j in range(w):
l[off+j*b+i*b*w] = l[off+j*b+i*b*w+3]

with open('threebody_new.bmp', 'wb') as f:
f.write(l)

希尔伯特曲线

reference: 真·降维打击!《三体》中二向箔吞噬地球的场景成真了!这位B站Up主过于硬核…… (qq.com)

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
import numpy as np
from PIL import Image
#安装:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple hilbertcurve
from hilbertcurve.hilbertcurve import HilbertCurve
#提取像素数据
with Image.open('threebody_new.png') as img:
arr = np.asarray(img)
arr = np.vectorize(lambda x: x&1)(arr[:,:,2])
#确定图片中的有效区域
for x1 in range(np.size(arr,0)):
if sum(arr[x1])>0:
break
for x2 in reversed(range(np.size(arr,0))):
if sum(arr[x2])>0:
break
for y1 in range(np.size(arr,1)):
if sum(arr[:,y1])>0:
break
for y2 in reversed(range(np.size(arr,1))):
if sum(arr[:,y2])>0:
break
#剪切出有效二维数据
arr = arr[x1:x2+1, y1:y2+1]
#print(x2+1-x1)#得出是128*128的矩阵
#构建希尔伯特曲线对象
hilbert_curve = HilbertCurve(7, 2)
#生成一维的二进制流数据
s = ''
for i in range(np.size(arr)):
[x,y] = hilbert_curve.point_from_distance(i)
s += str(arr[127-y][x])
#转ASCII文本写入文件
with open('output', 'wb') as f:
f.write(int(s,2).to_bytes(2048, 'big'))

但这个一直没能实现,不清楚是不是没剪切图片的原因。

0228,笑死,真的是因为没剪切的原因。

C语言编译

打开output.txt发现是C语言脚本,所以用VSCode进行编译运行,发现打印的是自身。

出题人的知识点:

这种可以打印自身的程序学名叫Quine

即使看似是相同的文件,可能存在某种差异,直接用BCompare4对原始文件以及输出文件进行对比,发现在文件的第11行存在差别。

原始文件存在Tab以及Space,转化成01数据流。

Notepad++得到01数据流。

1
01100110011011000110000101100111011110110100010000110001011011010100010101101110001101010110100100110000011011100100000101101100010111110101000001110010001100000011011000110001011001010110110101111101

数据处理

1
2
3
4
5
6
7
8
9
10
11
output = '2009092020090920200909200909202020090920202020092009092020090909200909090920090920092020200920202020090920202009200909200909200920092020200920092009092009090920202009092009200920090920092020092020090920202020200909200909092020092020202020092009092009092020200920090909090920092009202020202009090920200920202009092020202020200909200909202020090920202009200909202009200920090920090920092009090909092009'
import re
output = output.replace('20', '0').replace('09', '1')
# print(output)
# 01100110011011000110000101100111011110110100010000110001011011010100010101101110001101010110100100110000011011100100000101101100010111110101000001110010001100000011011000110001011001010110110101111101
a = re.findall(r'.{8}', output)
flag = ''
for i in a:
flag += ''.join(chr(int(i, 2)))
print(flag)
# flag{D1mEn5i0nAl_Pr061em}

[护网杯2018]easy_dump

利用vol查看镜像信息

vol.py -f easy_dump.img imageinfo

一般以镜像前1,2个操作系统为分析重点,eg: Win7SP1x64

指定镜像进行进程扫描

vol.py -f easy_dump.img --profile=WinSP1x64 pslist

vol.py -f easy_dump.img --profile=WinSP1x64 pstree

vol.py -f easy_dump.img --profile=WinSP1x64 psscan

发现可疑进程notepad.exe,那么我们直接把记事本内容给提取出来。

记事本内容dump

vol.py -f easy_dump.img --profile=Win7SP1x64 memdump -p 2616 -D ./

把记事本内容dump出来,利用string-grep对dmp文件内容进行检索。

记事本内容直接搜索

strings -eb 2616.dmp | grep flag

-el 也适用, -u相关用法不太不清楚具体案例,从而得到提示,找jpg文件。

根据提示查找图片并导出

vol.py -f easy_dump.img --profile=Win7SP1x64 filescan | grep .jpg

grep进行过滤,也可用其他形式进行检索,主体包含jpg即可。

vol.py -f easy_dump.img --profile=Win7SP1x64 dumpfiles -Q 0x000000002408c460 -D ./

直接导出的就是file:xxxx的格式,我们直接按照需求把文件改成原始文件名即可,eg: phos.jpg

图片隐写分析

有图片就回归到图片方面的隐写分析之上。

binwalk分析,发现存在zip,那么直接对其进行foremost提取。

提取出来一个message.img

再次进行提取操作,本次使用binwalk -e 进行提取hint.txt

使用foremost无法分离出来hint.txt文件

生成二维码

  • gnuplot转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
gnuplot         
G N U P L O T
Version 5.4 patchlevel 4 last modified 2022-07-10

Copyright (C) 1986-1993, 1998, 2004, 2007-2022
Thomas Williams, Colin Kelley and many others

gnuplot home: http://www.gnuplot.info
faq, bugs, etc: type "help FAQ"
immediate help: type "help" (plot window: hit 'h')

Terminal type is now 'qt'
gnuplot> plot'hint.txt'
gnuplot>

然后直接输出二维码图片

  • 脚本转换 暂且没成功…… -> 成功了,原终端为agg,无图形界面,需要切换为图形界面显示的终端TkAgg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import matplotlib.pyplot as plt
import matplotlib # keypoint
matplotlib.use('TkAgg') # keypoint
import numpy as np
x = []
y = []
with open('hint.txt', 'r') as f:
datas = f.readlines()
for data in datas:
arr = data.split(' ')
x.append(int(arr[0]))
y.append(int(arr[1]))

plt.plot(x, y, 'ks', ms=1)
plt.show()

扫描即可得到信息:1. 维吉尼亚密钥为aeolus 2. 加密后的密文被删除了

恢复镜像删除信息

使用testdisk进行恢复:testdisk message.img,进入相应的操作界面。

进入Proceed

进入None

因为涉及删除的文件,所以直接找该功能模块Undelete

找到标红处,说明该处存在删除文件。

c确定文件以及路径之后,出现该红框内内容说明导出成功。

到保存路径之下,使用ls -a发现保存下来的文件,直接利用strings查找字符串即可。

找到加密后的密文,使用在线解密网站结合密钥解密即可,最终得到相应的flag。

[国赛]everlasting_night

MD5免费在线解密破解_MD5在线加密-SOMD5

利用stegsolve得到隐藏密钥

  1. stegsolve导入图片,通过下方左右箭头进行查看,发现alpha 2通道右下角存在列向隐藏数据
  1. 选项卡Analyse的下拉列表选择Data Extract,得到f78dcd383f1b574b

!在靠近最下边,稍微仔细查看

cloacked-pixel提取lsb隐写文件

使用条件:

  1. 存在lsb隐写
  2. 得到密钥
  1. stegsolve无法提取lsb隐写文件+得到密钥,考虑另一种带密钥的lsb隐写,即cloacked-pixel
1
2
3
4
5
6
7
# python2实现
LSB steganogprahy. Hide files within least significant bits of images.

Usage:
lsb.py hide <img_file> <payload_file> <password>
lsb.py extract <stego_file> <out_file> <password>
lsb.py analyse <stego_file>
  1. 把图片放到cloacked-pixel路径之下,命令行输入python2 lsb.py extract 1.png flag.txt f78dcd383f1b574b
  1. 打开flag.txt,发现可能是zip,修改后缀名,得到flag.zip
  1. 解压缩,发现需要解压密钥,用winhex判断一下,发现应当是真加密。

winhex通过png文件尾得到一段MD5密文并解密

PNG (png):

文件头:89504E47文件尾:AE426082

  1. Winhex导入图片,选择左上角选项卡搜索,下拉框选择查找十六进制数据,输入png文件尾AE426082
  1. 发现png文件结束后,存在一段密文FB3EFCE4CEAC2F5445C7AE17E3E969AB
  1. 因为是32位的16进制字符串,一般先考虑是否是MD5密文,经过解密,得到一段密钥ohhWh04m1

MD5免费在线解密破解_MD5在线加密-SOMD5

cmd5.com无法解出。

  1. 利用该密钥对flag.zip进行解压缩得到flag

gimp打开图片并进行爆破

gimp为kali的PS处理软件

  1. 得到flag,winhex查看发现是应当是png文件,但修改后缀名发现无法打开
  2. 修改flag后缀名为.data,输入命令行gimp flag.data
  1. 发现图片需要处理,图形内容扭曲,一般考虑是高度不变,宽度改变。经过试验,宽度应当为352
  1. 得到flag{607f41da-e849-4c0b-8867-1b3c74536cc4}

[国赛]ez_usb

使用tshark对流量进行处理

winhex转换所得数据

Wireshark对流量包进行分组

usb.addr == “2.x.1”

usb.device_address == 4/8/10

  1. 分析流量包,发现host为2.10/4/8对应的infoURB_INTERRUPT,设置过滤规则,选中并导出相应的pcapng
1
usb.device_address == 4/8/10
  1. 分离好不同的流量包使用tshark对流量包数据进行处理
1
tshark -r 2_x.pcapng -T fields -e usbhid.data | sed '/^\s*$/d' > usb_x.txt
  1. 继续处理数据,利用脚本加上,分别导出文件output_x.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
f=open('usb_10.txt','r')
fi=open('output_10.txt','w')
while 1:
a=f.readline().strip()
if a:
if len(a)==16:
out=''
for i in range(0,len(a),2):
if i+2 != len(a):
out+=a[i]+a[i+1]+":"
else:
out+=a[i]+a[i+1]
fi.write(out)
fi.write('\n')
else:
break
fi.close()

使用键盘流量相关脚本对txt文件进行处理

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
normalKeys = {
"04":"a", "05":"b", "06":"c", "07":"d", "08":"e",
"09":"f", "0a":"g", "0b":"h", "0c":"i", "0d":"j",
"0e":"k", "0f":"l", "10":"m", "11":"n", "12":"o",
"13":"p", "14":"q", "15":"r", "16":"s", "17":"t",
"18":"u", "19":"v", "1a":"w", "1b":"x", "1c":"y",
"1d":"z","1e":"1", "1f":"2", "20":"3", "21":"4",
"22":"5", "23":"6","24":"7","25":"8","26":"9",
"27":"0","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t",
"2c":"<SPACE>","2d":"-","2e":"=","2f":"[","30":"]","31":"\\",
"32":"<NON>","33":";","34":"'","35":"<GA>","36":",","37":".",
"38":"/","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>",
"3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>",
"44":"<F11>","45":"<F12>"}
shiftKeys = {
"04":"A", "05":"B", "06":"C", "07":"D", "08":"E",
"09":"F", "0a":"G", "0b":"H", "0c":"I", "0d":"J",
"0e":"K", "0f":"L", "10":"M", "11":"N", "12":"O",
"13":"P", "14":"Q", "15":"R", "16":"S", "17":"T",
"18":"U", "19":"V", "1a":"W", "1b":"X", "1c":"Y",
"1d":"Z","1e":"!", "1f":"@", "20":"#", "21":"$",
"22":"%", "23":"^","24":"&","25":"*","26":"(","27":")",
"28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>",
"2d":"_","2e":"+","2f":"{","30":"}","31":"|","32":"<NON>","33":"\"",
"34":":","35":"<GA>","36":"<","37":">","38":"?","39":"<CAP>","3a":"<F1>",
"3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>",
"41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}
output = []
keys = open('output_x.txt') # 修改文件名进行运行
for line in keys:
try:
if line[0]!='0' or (line[1]!='0' and line[1]!='2') or line[3]!='0' or line[4]!='0' or line[9]!='0' or line[10]!='0' or line[12]!='0' or line[13]!='0' or line[15]!='0' or line[16]!='0' or line[18]!='0' or line[19]!='0' or line[21]!='0' or line[22]!='0' or line[6:8]=="00":
continue
if line[6:8] in normalKeys.keys():
output += [[normalKeys[line[6:8]]],[shiftKeys[line[6:8]]]][line[1]=='2']
else:
output += ['[unknown]']
except:
pass
keys.close()

flag=0
print("".join(output))
for i in range(len(output)):
try:
a=output.index('<DEL>')
del output[a]
del output[a-1]
except:
pass
for i in range(len(output)):
try:
if output[i]=="<CAP>":
flag+=1
output.pop(i)
if flag==2:
flag=0
if flag!=0:
output[i]=output[i].upper()
except:
pass
print('output :' + "".join(output))

分别对三个文本进行处理,最后2_4没跑出数据,2_8/2_10跑出数据

16进制/已知文件头将输出数据转换为压缩包,并解密

  1. 16进制转换

https://the-x.cn/encodings/Hex.aspx

  1. winhex
  1. 生成压缩包后,解压,使用所得密钥35c535765e50074a进行解密,得到flag{20de17cc-d2c1-4b61-bebd-41159ed7172d}

[国赛]pikalang

  1. stegsolvepika.png进行通道检查
  1. 提取出来的数据进行base64解密,得到pikalang密文
1
cGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGlrYSBwaXBpIHBpIHBpcGkgcGkgcGkgcGkgcGlwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaXBpIHBpIHBpIHBpIHBpIHBpIHBpIHBpIHBpIHBpIHBpIHBpY2h1IHBpY2h1IHBpY2h1IHBpY2h1IGthIGNodSBwaXBpIHBpcGkgcGlwaSBwaXBpIHBpIHBpIHBpa2FjaHUgcGkgcGkgcGkgcGkgcGkgcGkgcGlrYWNodSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBwaWthY2h1IHBpIHBpIHBpIHBpIHBpIHBpIHBpa2FjaHUgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGkgcGlrYWNodSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBrYSBwaWthY2h1IHBpY2h1IGthIGthIGthIGthIGthIGthIGthIGthIGthIGthIGthIGthIGthIGthIGthIGthIHBpa2FjaHUga2Ega2Ega2Ega2EgcGlrYWNodSBwaSBwaSBwaWthY2h1IHBpIHBpIHBpa2FjaHUgcGlwaSBwaWthY2h1IHBpY2h1IGthIGthIGthIGthIGthIHBpa2FjaHUgcGlwaSBwaSBwaSBwaWthY2h1IHBpY2h1IHBpIHBpIHBpIHBpa2FjaHUga2Ega2Ega2EgcGlrYWNodSBwaXBpIHBpa2FjaHUga2Ega2Ega2Ega2Ega2EgcGlrYWNodSBwaSBwaSBwaSBwaWthY2h1IHBpY2h1IGthIHBpa2FjaHUgcGkgcGkgcGkgcGlrYWNodSBrYSBwaWthY2h1IHBpcGkgcGkgcGlrYWNodSBwaWthY2h1IHBpY2h1IHBpIHBpa2FjaHUga2Ega2Ega2EgcGlrYWNodSBwaSBwaWthY2h1IHBpIHBpIHBpIHBpIHBpIHBpIHBpIHBpIHBpa2FjaHUga2Ega2Ega2Ega2Ega2Ega2EgcGlrYWNodSBwaXBpIHBpIHBpa2FjaHUgcGljaHUgcGlrYWNodSBwaXBpIGthIGthIGthIGthIGthIHBpa2FjaHUgcGkgcGkgcGkgcGkgcGkgcGlrYWNodSBwaWNodSBrYSBrYSBwaWthY2h1IHBpIHBpIHBpIHBpIHBpa2FjaHUga2EgcGlrYWNodSBrYSBrYSBrYSBrYSBwaWthY2h1IHBpIHBpIHBpIHBpIHBpIHBpIHBpIHBpIHBpa2FjaHUgcGlwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaSBwaWthY2h1IA==
  1. 引入第三方库pikalang,最后使用pokeball编写脚本
1
2
3
4
5
6
7
8
9
10
# import pikalang

sourcecode = """
pi pi pi pi pi pi pi pi pi pi pika pipi pi pipi pi pi pi pipi pi pi pi pi pi pi pi pipi pi pi pi pi pi pi pi pi pi pi pichu pichu pichu pichu ka chu pipi pipi pipi pipi pi pi pikachu pi pi pi pi pi pi pikachu ka ka ka ka ka ka ka ka ka ka ka pikachu pi pi pi pi pi pi pikachu pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pikachu ka ka ka ka ka ka ka ka ka ka ka ka ka ka ka ka ka ka ka ka ka ka ka pikachu pichu ka ka ka ka ka ka ka ka ka ka ka ka ka ka ka ka pikachu ka ka ka ka pikachu pi pi pikachu pi pi pikachu pipi pikachu pichu ka ka ka ka ka pikachu pipi pi pi pikachu pichu pi pi pi pikachu ka ka ka pikachu pipi pikachu ka ka ka ka ka pikachu pi pi pi pikachu pichu ka pikachu pi pi pi pikachu ka pikachu pipi pi pikachu pikachu pichu pi pikachu ka ka ka pikachu pi pikachu pi pi pi pi pi pi pi pi pikachu ka ka ka ka ka ka pikachu pipi pi pikachu pichu pikachu pipi ka ka ka ka ka pikachu pi pi pi pi pi pikachu pichu ka ka pikachu pi pi pi pi pikachu ka pikachu ka ka ka ka pikachu pi pi pi pi pi pi pi pi pikachu pipi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pikachu
"""

# or use sourcecode = pikalang.load_source("pika.pokeball") to load from file

pikalang.evaluate(sourcecode)

[网鼎杯 2020 青龙组]虚幻2

解压缩得到file

tools:

  1. winhex
  2. 中国编码APP
  3. pycharm

hint:

  1. 汉信码
  2. 爆破
  1. 使用winhex发现文件头是PNG,所以把后缀名修改,得到file.png
  2. file.png进行读取,得到01字符串
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
# 读取像素点
from PIL import Image

x = 36 #x坐标
y = 12 #y坐标

im=Image.open('file.png')
file = open('11', 'w')

#im.show()
z=''
for i in range(0, x):
for j in range(0, y):
rgb=im.getpixel((i, j))
print(rgb)
if(rgb[0]==0):
z+='1'
elif(rgb[0]==255):
z+='0'
if(rgb[1]==0):
z+='1'
elif(rgb[1]==255):
z+='0'
if(rgb[2]==0):
z+='1'
elif(rgb[2]==255):
z+='0'
print(z)
file.write(z)
  1. 01字符串写入图片,得到缺失一块的汉信码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 写入成为图片
from PIL import Image

x = 36 #x坐标
y = 36 #y坐标

im = Image.new("RGB", (x, y))
file = open('11', 'r')

a=file.read()
z=0
for i in range(0, x):
for j in range(0, y):
print(a[z])
if(a[z]=='1'):
im.putpixel((i, j), (255, 255, 255))
elif(a[z]=='0'):
im.putpixel((i, j), (0, 0, 0))
z=z+1

im.show()
im.save('Hanxin.png')
  1. 稍微补充点,然后让汉信码自动校正。得到flag{eed70c7d-e530-49ba-ad45-80fdb7872e0a}

电子数据取证-Volatility

1. Suspicion

解压缩得到mem.vmem suspious

tools:

  1. vol.py
  2. Elcomsoft Forensic Disk Decryptor(EFDD)
  1. 通过vol.py -f mem.vmem imageinfo获得基本信息
  1. 通过vol.py -f mem.vmem --profile=WinXPSP2x86 pstree,得到加密进程TrueCrypt.exe,推断suspious是加密后的数据
  1. 通过vol.py -f mem.vmem --profile=WinXPSP2x86 memdump -p 2012 -D ./(-p为PID,-D是转储路径)
  1. 使用EFDD2012.dmp进行解密以及挂载。

进行挂载操作。

  1. 查看挂载后的数据,找到PCTF{T2reCrypt_15_N07_S3cu2e}

2. [湖湘杯2020] passwd

解压缩得到WIN-BU6IJ7FI9RU-20190927-152050.raw

MD5解密

  1. 依旧查看基本信息vol.py -f WIN-BU6IJ7FI9RU-20190927-152050.raw imageinfo
  1. 查看hash值vol.py -f WIN-BU6IJ7FI9RU-20190927-152050.raw --profile=Win7SP1x86_23418 hashdump
  1. 使用MD5网站进行解密,得到qwer1234

3. [NEWSCTF2021] very-ez-dump

解压缩得到mem.raw

  1. 查看镜像信息vol.py -f mem.raw imageinfo
  1. 查看cmd所执行的相关命令,发现添加了一个用户mumuzi且密码为(ljmmz)ovo
  1. 查找flag关键词vol.py -f mem.raw --profile=Win7SP1x64 filescan | grep flag,发现flag.zip进行转储vol.py -f mem.raw --profile=Win7SP1x64 dumpfiles -Q 0x000000003e4b2070 -D ./(-Q为地址,-D为转储路径)
  1. winhex发现应该是zip,修改后缀名,发现压缩包进行真加密,并且需要相应的密码。
  1. 用2中得到的密码对压缩包进行解密,最后解密得到flag{ez_di_imp_1t_y0u_like?}

5. [HDCTF2019]你能发现什么蛛丝马迹吗

解压缩得到memory.img

tools:

  1. volatility
  1. 正常流程,先看具体里面内容vol.py -f memory.img imageinfo

主要使用了Win2003SP,根据尝试,发现Win2003SP0x86无法读取相关的数据,所以主要选择Win2003SP1x86等进行内存取证。

  1. 使用vol.py -f memory.img --profile=Win2003SP1x86 sptree查看进程。发现两个可疑进程ctfmoon.exeDumpIt.exe,ctfmoon.exe进程相对久远,优先查看DumpIt.exe

DumpIt.exe主要是用来内存取证的工具,那主要的思路就是查看它主要做了哪些工作。

  1. 使用screenshot查看vol.py -f memory.img --profile=Win2003SP1x86 screenshot --dump-dir=./
  1. 发现了flag.png,此时主要查找相关的flagvol.py -f memory.img --profile=Win2003SP1x86 filescan | grep flag
  1. vol.py -f memory.img --profile=Win2003SP1x86 dumpfiles -Q 0x000000000484f900 -D ./ -u

flag相关给导入数据,最后得到00.dat

二维码扫一扫发现一段疑似base64密文。但解密没得到有用数据,于是继续从别的渠道查看。

  1. 查看打开了哪些软件以及具体操作vol.py -f memory.img --profile=Win2003SP1x86 windows

Pid:1992,使用图片和传真查看器查看了flag.png

  1. 然后我们把这些相关数据给导出 vol.py -f memory.img --profile=Win2003SP1x86 memdump -p 1992 -D ./,从而得到1992.dmp

  2. 我们得到1992.dmp后,利用foremost 1992.dmp把隐藏其中的相关数据给导出

里面发现这些图片。

二维码就是之前分离出来的,扫出来是jfXvUoypb8p3zvmPks8kJ5Kt0vmEw0xUZyRGOicraY4=,而另一张图显示key:Th1s_1s_K3y00000以及iv:1234567890123456。出现IV+密文也是base64形式。所以考虑是否进行了AES加密。

  1. 对密文进行AES解密,因为告诉了IV所以主要考虑是不是除了ECB以外的模式,但最终其实就是ECB模式的AES解密。(所以这一步很迷,给的IV难道就只是提示AES?)

AES解密:在线AES加密解密、AES在线加密解密、AES encryption and decryption–查错网 (chacuo.net)

最后得到密文flag{F0uNd_s0m3th1ng_1n_M3mory}

-------------THE END-------------