战队名:超级飞侠
撰写时间:2022-07-16 20:43

强国杯【线上-2022】

I. WEB

【upload_lol】

考点

  • 上传绕过

    解法

  • 经过多次测试发现,文件后缀不能带有php,文件内容不能有<? ,而?>这个好像没有过滤,文件类型改为image/jpeg即可;所以先上传一个.htaccess,内容为

    1
    2
    AddType application/x-httpd-php .jpg
    php_value auto_append_file "php://filter/convert.base64-decode/resource=shell.jpg"
  • 然后在shell.jpg文件里面写入base64加密过的一句话木马

  • 蚁剑连上在var目录下得到flag

【file_sql_new】

考点

  • 字符型注入

  • 过滤绕过

    解法

  • 字符型注入,过滤了select,会替换为空,双写select绕过,回显2、3字段

  • 爆表名

  • 爆列名

  • 获取flag路径

  • 使用load_file读取flag


II. MISC

【welcome_to_QGB】

考点

  • base64解码

    解法

  • 将字符串V2VsY29tZV90b19RR0I=进行base64解码再套上flag{}格式即可

【B@tCh】

考点

  • BatchEncryption混淆还原

    解法

  • 文本工具打开显示乱码,改用二进制工具winhex,发现文件头为FFFE,即unicode编码的小端UTF-16,批处理为ansi,所以直接将FFFE改成2020,即可用文本工具打开

  • 使用下面脚本进行解(使用该脚本,需要将文件前面的如&cls等内容去掉,从@%os开始,因为我懒得写识别了,所以将正文直接从0字符开始获取),得出flag

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
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Batch Decryption 202009 (BatchEncryption Build 201610)
#

import os

vars = {}

# decryption line
i = 0
l = len(data)
while i < l:
i = run(vars, data, i)

def run(vars, data, i):
buf = ''
f = 0
t = 0
x = False
l = len(data)
while(True):
if data[i] == 0x0d and data[i+1] == 0x0a:
i += 2
break
# get %var:~x,y% %0
if data[i] == 0x25:
if not x:
x = True
f = i
else:
x = False
t = i
rst = var_percent(data[f:t+1], vars)
buf += rst
else:
if not x:
buf += str(data[i:i+1], encoding="utf-8")
else:
if (f + 1 == i) and ((data[i] >= 0x30 and data[i] <= 0x39) or data[i] == 0x2a):
x = False
t = i
rst = str(data[f:t+1], encoding="utf-8")
buf += rst
i += 1
if i >= l:
break
#
print(buf)
bufs = buf.split('&@')
for var in bufs:
if var[0:4] == 'set ':
var = var[4:]
b = var.find('=')
vars[var[0:b]] = var[b+1:].replace('^^^', '^')

return i

def var_percent(data, vars):
full = str(data, encoding="utf-8")
buf = full[1:len(full)-1]
buf = buf.split(':~')
var = buf[0]
if not var in vars:
vars[var] = os.getenv(var)
ent = vars[var]
if (len(buf) > 1):
l = len(ent)
buf = buf[1].split(',')
f = int(buf[0])
t = int(buf[1])
if f < 0:
f, t = l + f, t
rst = ent[f: f+t]
else:
rst = full
return rst

encrypt_file = '此处填写bat文件路径'

if __name__ == '__main__':

try:
file = open(encrypt_file, "rb")
data = file.read()
except Exception as err:
print('Batch decryption read error:', err)
exit
else:
file.close()

decryption(data)

【找找GIF】

考点

  • 动图分析

  • 文件头识别

    解法

  • 题目提示动图分析

  • aaa文件是png图片,修改高后发现密码

  • 使用密码fjgk90^&vvvfdd解压bbb.zip得到bbb文件,分析bbb文件发现是gif图片,但缺少文件头

  • 添加文件头,使用stegsolve分析得到flag

【大佬大佬】

考点

  • lsb隐写

  • 修改图片高度

    解法

  • 题目提示获取图片的lsb隐写,修改图片尺寸,stegsolve分析获取png图片

  • 修改图片高度获取flag

【The fun picture】

考点

  • 压缩包密码爆破

  • 图片分析识别

    解法

  • 题目提示简单的图片分析,解压题目附件提示要密码,爆破出密码为gh89

  • 题目有三个文件,FUN.png是压缩包,解压出个flag6文件

  • flag6是个png图片,添加文件头,打开是二维码

  • 扫描得到一串base64字符串解码得到flag


IV. CRYPTO

【babyRSA】

考点

  • 解法

  • 根据给出的数据发现少了N,而根据RSA算法得知

  • N = q * p

  • r = (p -1) * (q - 1) 求得关于r求e的模逆元D

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

import gmpy2
import binascii

P=122661900225958537473593999629721155547445152508344628379156151659796333424765145214036218314036538367449542188442412001233407797975924025535192193558685614179856037200129145911423039793961531441773477698026833665056111228506730246279582720435235709543855376031268946650792983451355568301885456994665262875749

Q=152724789318100477389853045726902882371493936383383619555088124064539207319241990180547432685312774553372809313491471789726609450644068056661970298474939384495232219405764685450242448624149384201199927977364779992607712253080589100019883370160068766123718298014862011278111513825917110130106578782458953059859

E=33
N = P * Q
C=11852026632281701016724299626853609925180998208455660311000462227020929333377781887963495074427303581997467868526563174560178272022772274396432682692794063165224973938499915472777760940556428251371134510052503881386517887007288504116932135535735038891342756359104150065602002052735935730495500714873277911540993054971564663909394753577934282562474400064427000243598933915050367444422905464938144621404295662232927161154426321727883942392656517143955794390377418120483810457172329736269488772672472120992463072392783584779323287481047740952196227038157414187174528649660615317679662848063671637919176651288177629770199

D = gmpy2.invert(E, (P - 1) * (Q - 1))

decData = gmpy2.powmod(C,D,N)

print(binascii.unhexlify(hex(decData)[2:]))
  • 求得flag

Ⅴ.Reverse

【encrypt】

考点

总结
  1. 统计词频
  2. 对数据进行编码
  3. 对数据换表后写出
  4. 通过简单的算法计算v25,把v32 和 v25的数据做差后的数据写出
    • 文件的大致结构

      1
      2
      3
      4
      5
      6
      7
      8
      typedef struct File{
      int magic = 0x666C6167;
      unsigned short frequency_table_size;
      unsigned char *frequency_table;
      unsigned int origin_file_size;
      unsigned char *code_data;
      unsigned short check;
      }File;
思路
  • 获取词频表,对其换表

  • 使用程序中的算法将原数据转换成插值编码

  • 根据哈夫曼压缩原理将每个数据的比特位进行比较

  • 写出数据

  • 解密脚本

    1. 脚本1
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

from ctypes import *
import os
import struct
from typing import Any

class Node:
def __init__(self, data: Any, left, right) -> None:
self.data = data
self.left: Node = left
self.right: Node = right

def is_leaf(self):
return self.left == None and self.right == None

const = [
0x14, 0x62, 0xe3, 0x8d, 0x32, 0x9e, 0xdb, 0x63, 0x5e, 0x82, 0x53, 0xd5, 0x89, 0xcc, 0x2b, 0xbc,
0x69, 0x7d, 0x4d, 0x37, 0x28, 0xb2, 0xef, 0x46, 0xed, 0x2a, 0xde, 0xc6, 0x8a, 0x44, 0x7a, 0x61,
0xae, 0x13, 0x52, 0x70, 0xbf, 0xe6, 0x1f, 0xaf, 0x90, 0x97, 0x9a, 0xf7, 0x31, 0x43, 0xc1, 0xf3,
0xa6, 0xb4, 0xa8, 0x30, 0x9b, 0xab, 0x00, 0xcd, 0xb3, 0xe1, 0x7c, 0x39, 0xfc, 0xc7, 0x94, 0x3c,
0x71, 0x7e, 0x19, 0xdd, 0x05, 0xb6, 0x10, 0x8f, 0xd9, 0x4c, 0x40, 0x9f, 0xdf, 0x41, 0x6d, 0x1d,
0x45, 0xa1, 0xb1, 0x8e, 0x8b, 0xff, 0x1e, 0x34, 0xa5, 0x4a, 0x96, 0x0a, 0xdc, 0x08, 0xd7, 0xe9,
0x20, 0x15, 0xcf, 0xb9, 0xd6, 0xb8, 0xbd, 0x26, 0x77, 0x80, 0x2f, 0xd1, 0xc3, 0x17, 0x68, 0x56,
0x98, 0x0d, 0x42, 0x91, 0x83, 0x54, 0x5c, 0xb5, 0xf0, 0x50, 0x79, 0xe7, 0xa2, 0x60, 0x6e, 0xa9,
0x16, 0xf6, 0xd0, 0x47, 0xf2, 0x48, 0x0e, 0x18, 0xc8, 0x3b, 0xb0, 0x38, 0x0b, 0x67, 0xaa, 0x24,
0x1c, 0xfa, 0x5f, 0x5b, 0x06, 0x36, 0xa3, 0x03, 0x59, 0x5a, 0x87, 0x23, 0x2c, 0x73, 0x12, 0xf8,
0xfd, 0xce, 0x93, 0xfb, 0x49, 0x57, 0xc9, 0x6a, 0x6b, 0xe2, 0xac, 0x07, 0x88, 0x84, 0xd8, 0xeb,
0x2d, 0xd3, 0x92, 0x21, 0x99, 0x81, 0x78, 0xba, 0xe5, 0x85, 0x65, 0xe0, 0x5d, 0xbe, 0xa4, 0x4e,
0xf1, 0x4f, 0x51, 0x64, 0x0f, 0x35, 0x76, 0x6c, 0xf9, 0x3a, 0x27, 0xc5, 0xf5, 0xda, 0xa7, 0x95,
0xcb, 0x25, 0x9d, 0xca, 0x75, 0xb7, 0x9c, 0x1b, 0x0c, 0x7b, 0x58, 0x3e, 0xe4, 0x2e, 0x3f, 0x55,
0xee, 0x4b, 0x09, 0xfe, 0x1a, 0x7f, 0xa0, 0x29, 0xea, 0xc4, 0x8c, 0x86, 0x3d, 0xad, 0xe8, 0x66,
0x6f, 0x33, 0x02, 0xd2, 0xec, 0x22, 0xf4, 0xd4, 0x01, 0xc2, 0x74, 0xbb, 0xc0, 0x04, 0x72, 0x11
]

r_const = [0]*256

out_data = []

def read_file(path: str):
with open(path, 'rb') as f:
return f.read()

def build_haffuman(node: Node, frequency_table):
for i, v in enumerate(frequency_table):
cur = node
for j in v:
new = Node(None, None, None)

if j == '0':
if cur.left != None:
new.left = cur.left.left
new.right = cur.left.right

cur.left = new
else:
if cur.right != None:
new.left = cur.right.left
new.right = cur.right.right

cur.right = new

cur = new

cur.data = i

# 解析文件结构
file = read_file(os.path.join(os.getcwd(), 'input.crypt'))
offset = 4

frequency_table_size = c_uint16(
struct.unpack_from('<H', file, offset)[0]).value
offset += 2

frequency_table = list(file[offset:offset + frequency_table_size])
offset += frequency_table_size
print(f"Frequncy table size: {frequency_table_size}")

ori_file_size = c_uint16(struct.unpack_from('<I', file, offset)[0]).value
offset += 4

print(f"Origin file size: {ori_file_size}")

zip_data = list(file)[offset: offset + ori_file_size]

# 对词频表进行换表
for i, v in enumerate(const):
r_const[v] = i

for i, v in enumerate(frequency_table):
frequency_table[i] = r_const[v]

# 生成每个编码做差值后的编码
total = c_uint32(0)

each_data_to_save = c_uint8(0)

code_array = [0] * 256

for i in range(256):
index = i

total = 0
j = 0

while True:
if total + (1 << j) > index:
break
total += (1 << j)
j += 2

each_data_to_save.value = 1 << j

each_data_to_save.value = (index - total)

bin_data = bin(each_data_to_save.value)[2:]

count_bit_save = int(5 + j / 2)

for i in range(count_bit_save - len(bin_data)):
bin_data = '0' + bin_data

if count_bit_save == 9:
bin_data = '1' + bin_data[1:]

code_array[index] = bin_data

# 构建哈夫曼树
haffuman = Node(None, None, None)
build_haffuman(haffuman, code_array)

# 对数据转换成比特位
zip_data = [bin(i)[2:] for i in zip_data]

for i, v in enumerate(zip_data):
k = v
for j in range(8 - len(v)):
k = '0' + k
zip_data[i] = k
zip_data = ''.join(zip_data)

# 根据哈夫曼树解码数据
pos = 0
cur = haffuman
data = []
while pos < len(zip_data):

if cur.is_leaf():
data.append(frequency_table[cur.data])
cur = haffuman

if zip_data[pos] == '0':
cur = cur.left
else:
cur = cur.right

pos += 1

# 写出文件
with open(os.path.join(os.getcwd(), 'out.bin'), 'wb') as f:
f.write(bytes(data))
  1. 脚本2
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
from ctypes import *
import os
import struct

const = [
0x14, 0x62, 0xe3, 0x8d, 0x32, 0x9e, 0xdb, 0x63, 0x5e, 0x82, 0x53, 0xd5, 0x89, 0xcc, 0x2b, 0xbc,
0x69, 0x7d, 0x4d, 0x37, 0x28, 0xb2, 0xef, 0x46, 0xed, 0x2a, 0xde, 0xc6, 0x8a, 0x44, 0x7a, 0x61,
0xae, 0x13, 0x52, 0x70, 0xbf, 0xe6, 0x1f, 0xaf, 0x90, 0x97, 0x9a, 0xf7, 0x31, 0x43, 0xc1, 0xf3,
0xa6, 0xb4, 0xa8, 0x30, 0x9b, 0xab, 0x00, 0xcd, 0xb3, 0xe1, 0x7c, 0x39, 0xfc, 0xc7, 0x94, 0x3c,
0x71, 0x7e, 0x19, 0xdd, 0x05, 0xb6, 0x10, 0x8f, 0xd9, 0x4c, 0x40, 0x9f, 0xdf, 0x41, 0x6d, 0x1d,
0x45, 0xa1, 0xb1, 0x8e, 0x8b, 0xff, 0x1e, 0x34, 0xa5, 0x4a, 0x96, 0x0a, 0xdc, 0x08, 0xd7, 0xe9,
0x20, 0x15, 0xcf, 0xb9, 0xd6, 0xb8, 0xbd, 0x26, 0x77, 0x80, 0x2f, 0xd1, 0xc3, 0x17, 0x68, 0x56,
0x98, 0x0d, 0x42, 0x91, 0x83, 0x54, 0x5c, 0xb5, 0xf0, 0x50, 0x79, 0xe7, 0xa2, 0x60, 0x6e, 0xa9,
0x16, 0xf6, 0xd0, 0x47, 0xf2, 0x48, 0x0e, 0x18, 0xc8, 0x3b, 0xb0, 0x38, 0x0b, 0x67, 0xaa, 0x24,
0x1c, 0xfa, 0x5f, 0x5b, 0x06, 0x36, 0xa3, 0x03, 0x59, 0x5a, 0x87, 0x23, 0x2c, 0x73, 0x12, 0xf8,
0xfd, 0xce, 0x93, 0xfb, 0x49, 0x57, 0xc9, 0x6a, 0x6b, 0xe2, 0xac, 0x07, 0x88, 0x84, 0xd8, 0xeb,
0x2d, 0xd3, 0x92, 0x21, 0x99, 0x81, 0x78, 0xba, 0xe5, 0x85, 0x65, 0xe0, 0x5d, 0xbe, 0xa4, 0x4e,
0xf1, 0x4f, 0x51, 0x64, 0x0f, 0x35, 0x76, 0x6c, 0xf9, 0x3a, 0x27, 0xc5, 0xf5, 0xda, 0xa7, 0x95,
0xcb, 0x25, 0x9d, 0xca, 0x75, 0xb7, 0x9c, 0x1b, 0x0c, 0x7b, 0x58, 0x3e, 0xe4, 0x2e, 0x3f, 0x55,
0xee, 0x4b, 0x09, 0xfe, 0x1a, 0x7f, 0xa0, 0x29, 0xea, 0xc4, 0x8c, 0x86, 0x3d, 0xad, 0xe8, 0x66,
0x6f, 0x33, 0x02, 0xd2, 0xec, 0x22, 0xf4, 0xd4, 0x01, 0xc2, 0x74, 0xbb, 0xc0, 0x04, 0x72, 0x11
]

r_const = [0]*256

out_data = []

def read_file(path: str):
with open(path, 'rb') as f:
return f.read()

# 解析文件结构
file = read_file(os.path.join(os.getcwd(), 'input.crypt'))
offset = 4

frequency_table_size = c_uint16(struct.unpack_from('<H', file, offset)[0]).value
offset += 2

frequency_table = list(file[offset:offset + frequency_table_size])
offset += frequency_table_size
print(f"Frequncy table size: {frequency_table_size}")

ori_file_size = c_uint16(struct.unpack_from('<I', file, offset)[0]).value
offset += 4

print(f"Origin file size: {ori_file_size}")

zip_data = list(file)[offset: offset + ori_file_size]

# 对词频表进行换表
for i, v in enumerate(const):
r_const[v] = i

for i, v in enumerate(frequency_table):
frequency_table[i] = r_const[v]

# 生成每个编码做差值后的编码
total = c_uint32(0)

each_data_to_save = c_uint8(0)

code_array = [0] * 256

for i in range(256):
index = i

total = 0
j = 0

while True:
if total + (1 << j) > index:
break
total += (1 << j)
j += 2

each_data_to_save.value = 1 << j

each_data_to_save.value = (index - total)

bin_data = bin(each_data_to_save.value)[2:]

count_bit_save = int(5 + j / 2)

for i in range(count_bit_save - len(bin_data)):
bin_data = '0' + bin_data

if count_bit_save == 9:
bin_data = '1' + bin_data[1:]

code_array[index] = bin_data

# 对数据部转换成比特位
zip_data = [bin(i)[2:] for i in zip_data]

for i, v in enumerate(zip_data):
k = v
for j in range(8 - len(v)):
k = '0' + k
zip_data[i] = k
zip_data = ''.join(zip_data)

# 解析比特位
size = 0
current_data = ''
data = []
while size < ori_file_size:
current_data += zip_data[0]
if current_data in code_array:
data.append(frequency_table[code_array.index(current_data)])
size += 1
current_data = ''
zip_data = zip_data[1:]

# 写出文件
with open(os.path.join(os.getcwd(),'out.bin'),'wb') as f:
f.write(bytes(data))