[Week1] Ez Xor

这里是加密后的东西,由于是局部变量,直接变成一坨了,我们把它弄出来就行,或者直接动态调试,从hex-view里面找,也是很方便的。
2024-09-22T12:16:13.png

from regadgets import *

# data
enc = qword2byte([0x1D0B2D2625050901, 0x673D491E20317A24, 0x34056E2E2508504D])
enc += b"\"@;%"
assert len(enc) == 28

# keystream
k = b'Xor'
keyStream = bytes([i ^ k[i % len(k)] for i in range(len(enc))])

# xor
print(bxor(enc, keyStream[::-1]))
# b'BaseCTF{X0R_I5_345Y_F0r_y0U}'

[Week1] You are good at IDA

2024-09-22T12:22:51.png
Y0u_4Re_
2024-09-22T12:23:41.png
900d_47_
2024-09-22T12:24:18.png
id4
BaseCTF{Y0u_4Re_900d_47_id4}

[Week1] BasePlus

2024-09-22T12:26:23.png
Encode 里面经过分析是一个Base64 encode
Secret是/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC
也就是一个换表Base64,不过base64里面偷偷给你异或了一个0xE,这个要注意

from regadgets import *
enc = b'lvfzBiZiOw7<lhF8dDOfEbmI]i@bdcZfEc^z>aD!'
k = 0xe
dec = decode_b64(bxor(enc, [k for _ in range(len(enc))]).decode(),
                  '/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC')

print(dec)
# b'BaseCTF{BA5e_DEcoD1N6_sEcr3t}\x00'

[Week1] UPX mini

UPX 解压
2024-09-22T12:31:39.png
2024-09-22T12:32:02.png
base64_encode,名字没有清理掉,而且进去是标准base64

from regadgets import *
enc = 'QmFzZUNURntIYXYzX0BfZzBvZF90MW0zISEhfQ=='
dec = decode_b64(enc)
print(dec)
# b'BaseCTF{Hav3_@_g0od_t1m3!!!}'

[Week1] ez_maze

2024-09-22T12:35:53.png
进去之后分析一下,把一些字符还原了,wasd,这几个分别是上左下右,看起来是没问题的
显然迷宫是用一个数组进行存储,pos % 15 == 14可以知道迷宫行宽15(因为pos从0开始), pos > 209可知道迷宫总共210个数,也就是15*14的迷宫
2024-09-22T12:38:29.png
然后如果是y就是终点,如果是$就是invalid(墙壁,不能走)。
我们提取出来,看一看

>>> a = "x$$$$$$$$$$$$$$&&&&&&$$$$$$$$$&$&$$&$$&&&&&$$&$&$$$&&$$$$&$$&$$$&&&$$$$$&$$&$$$&$&&$&$$$$$&$$$&$&$$&&&$$$&&&&&$&&&&$&$$$$$$$$$&&&&&&$$$$$$$$$&$$$$$$$$$$$&&&&$$&&&$$$$$$&&&&&&&$$$$$$$$$$$$$$&$$&$$$$$$$$$$$&$&$$$$$$$$$&&&&&&&&y"
>>>
>>> for i in range(0, len(a), 15):
...     print(a[i:i+15])
...
x$$$$$$$$$$$$$$
&&&&&&$$$$$$$$$
&$&$$&$$&&&&&$$
&$&$$$&&$$$$&$$
&$$$&&&$$$$$&$$
&$$$&$&&$&$$$$$
&$$$&$&$$&&&$$$
&&&&&$&&&&$&$$$
$$$$$$&&&&&&$$$
$$$$$$&$$$$$$$$
$$$&&&&$$&&&$$$
$$$&&&&&&&$$$$$
$$$$$$$$$&$$&$$
$$$$$$$$$&$&$$$
$$$$$$&&&&&&&&y
>>>

然后使用notepad++进行标记,手动走一下
2024-09-22T12:40:40.png
sssssssddddwwwddsssssssdddsssddddd
然后程序提示,flag是BaseCTF{md5(path)}
所以

from hashlib import md5
print(f"BaseCTF{{{md5(b'sssssssddddwwwddsssssssdddsssddddd').hexdigest()}}}")
# BaseCTF{131b7d6e60e8a34cb01801ae8de07efe}

[Week2] Ezpy

┌──(Administrator💀NullCafe)-[ base]-[~/Desktop/BaseCTF2024/Reverse/[Week2] Ezpy]                               0ms  
└─#  python .\pyinstxtractor.py .\Ezpy.exe
[+] Processing .\Ezpy.exe
[+] Pyinstaller version: 2.1+
[+] Python version: 3.9
[+] Length of package: 5835441 bytes
[+] Found 59 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: Ezpy.pyc
[!] Warning: This script is running in a different Python version than the one used to build the executable.
[!] Please run this script in Python 3.9 to prevent extraction errors during unmarshalling
[!] Skipping pyz extraction
[+] Found 81 files in PYZ archive
[+] Successfully extracted pyinstaller archive: .\Ezpy.exe

注意到

[!] Warning: This script is running in a different Python version than the one used to build the executable.
[!] Please run this script in Python 3.9 to prevent extraction errors during unmarshalling
[!] Skipping pyz extraction

这个其实是因为你python版本不对导致的,我们可以修改pyinstxtractor.py让它不跳过一些pyc的提取,也可以换python版本,我们这里为了反编译更完美,选择更换python版本。
我是用conda进行多版本python环境共存。
2024-09-22T12:49:30.png
可以注意到,是python3.9.7,所以我们安装
conda create -n py397 python=3.9.7
然后切换
conda activate py397

┌──(Administrator💀NullCafe)-[ py397]-[~/Desktop/BaseCTF2024/Reverse/[Week2] Ezpy]                             37ms  
└─#  python .\pyinstxtractor.py .\Ezpy.exe
[+] Processing .\Ezpy.exe
[+] Pyinstaller version: 2.1+
[+] Python version: 3.9
[+] Length of package: 5835441 bytes
[+] Found 59 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: Ezpy.pyc
[+] Found 81 files in PYZ archive
[+] Successfully extracted pyinstaller archive: .\Ezpy.exe

You can now use a python decompiler on the pyc files within the extracted directory

这下就完美了,我们使用pycdc来反编译
2024-09-22T12:51:53.png

# Source Generated with Decompyle++
# File: Ezpy.pyc (Python 3.9)

import Key
import sys

def init_Sbox(seed):
    k_b = (lambda .0 = None: [ ord(seed[i % len(seed)]) for i in .0 ])(range(256))
    s = list(range(256))
    j = 0
    for i in range(256):
        j = (j + s[i] + k_b[i]) % 256
        s[i] = s[j]
        s[j] = s[i]
    return s


def KeyStream(text, Sbox):
    s = Sbox.copy()
    (i, j) = (0, 0)
    k = [
        0] * len(text)
    for r in range(len(text)):
        i = (i + 1) % 256
        j = (j + s[i]) % 256
        s[i] = s[j]
        s[j] = s[i]
        t = (s[i] + s[j]) % 256
        k[r] = s[t] ^ Key.keykey[r % len(Key.keykey)]
    return k


def Encrypt(text, seed):
    Sbox = init_Sbox(seed)
    key = KeyStream(text, Sbox)
    enc = (lambda .0 = None: [ text[i] ^ key[i] for i in .0 ])(range(len(text)))
    return bytes(enc)

enc = b'\xe6\xaeC~F\xf2\xe3\xbb\xac\x9a-\x02U\x85p\xeb\x19\xd1\xe4\xc93sG\xb0\xeb1\xb5\x05\x05\xc3\xd7\x00\x18+D\xbc\x0cO\x9em\xf1\xbd'
flag = input('Please input Your flag:')
flag = (lambda .0: [ ord(i) for i in .0 ])(flag)
flag = Encrypt(flag, Key.key)
if flag != enc:
    print("It's not flag!")
    continue
print('You are right!')
sys.exit(1)
continue

可以注意到,init_Sbox是RC4的init,KeyStream是在获取RC4的密钥流。
不过我们还需要知道Key.key,keykey这俩是什么
我们在子目录下找到Key.pyc,进行反编译

└─# C:\Users\Administrator\Desktop\Reverse\Python\pycdc\pycdc.exe .\Key.pyc
# Source Generated with Decompyle++
# File: Key.pyc (Python 3.9)

key = 'yOU_f1nd_m3'
keykey = [
    66,
    97,
    115,
    101]

exp

from regadgets import *
key = 'yOU_f1nd_m3'
keykey = [
    66,
    97,
    115,
    101]
enc = b'\xe6\xaeC~F\xf2\xe3\xbb\xac\x9a-\x02U\x85p\xeb\x19\xd1\xe4\xc93sG\xb0\xeb1\xb5\x05\x05\xc3\xd7\x00\x18+D\xbc\x0cO\x9em\xf1\xbd'

s = rc4_init(key.encode())
keystream = list(rc4_keystream(s, len(enc)))
keystream = bxor_cycle(keystream, keykey)
print(bxor(keystream, enc))
# b'BaseCTF{Y0u_kn0W_d3C0Mp1l4710N_PY_4ND_rC4}'

不过这里我推荐使用黑手办法
我们使用hypno进行注入

>>> from hypno import *
>>> code = """
... Sbox = init_Sbox(Key.key)
... keys = KeyStream("a"*len(enc), Sbox)
... print(keys)
... """
>>>
>>> inject_py(9024, code)

2024-09-22T13:14:58.png
然后就能得到KeyStream,注入原理是,attach到Python39.dll然后

void run_python_code() {
    if (PYTHON_CODE[0]) {
        int saved_errno = errno;
        PyGILState_STATE gstate = PyGILState_Ensure();
        PyRun_SimpleString(PYTHON_CODE);
        PyGILState_Release(gstate);
        errno = saved_errno;
    }
}

通过调用PyRun_SimpleString就可以执行代码注入。
然后我们继续
exp

from regadgets import *
enc = b'\xe6\xaeC~F\xf2\xe3\xbb\xac\x9a-\x02U\x85p\xeb\x19\xd1\xe4\xc93sG\xb0\xeb1\xb5\x05\x05\xc3\xd7\x00\x18+D\xbc\x0cO\x9em\xf1\xbd'
box = [164, 207, 48, 27, 5, 166, 165, 192, 245, 170, 88, 93, 62, 235, 64, 188, 70, 181, 215, 138, 3, 62, 55, 129, 135, 5, 130, 52, 53, 141, 136, 80, 65, 116, 112, 242, 72, 16, 236, 46, 197, 192]
print(bxor(enc, box))
# b'BaseCTF{Y0u_kn0W_d3C0Mp1l4710N_PY_4ND_rC4}'

注入应该是解决这种类型题目的最优雅的办法。

[Week2] RivestCipher

题目名字明示是rc4,但是我们还是看一看
2024-09-22T13:45:17.png
main_main,是go编译的产物
由于ida对go的字符串支持不太行(因为go的字符串和rust的一样,都是连着的而不是x00截断)
我们直接看流程图
2024-09-22T13:46:35.png
可以看到这里,mov ecx, 7代表后面的字符串长度7
所以字符串是BaseCTF
2024-09-22T13:48:44.png
下面直接进rc4加密函数了,所以大概率是key
2024-09-22T13:51:09.png
很清晰,所以我就直接写wp了(enc是后面的hex字符串 可以直接找到)

from regadgets import *
enc = bytes.fromhex('0ebb0c573dd548f3d2b2525f02895cd5275b6f6e5776538982ea41246dae8517')
s = rc4_init(b'BaseCTF')
print(rc4_crypt(s, enc))
# b'BaseCTF{go1@ng_!S_RuNNin9_RC4}\r\n'

[Week2] UPX

x64dbg 零帧起手,找到个

$rg7_dhd~Alidg+zeyhz`vnz_d,7sy0=

这时候我就已经猜到是魔改base64了,但是还是继续看看
2024-09-22T14:07:37.png
果然找到base64表(& 0x3f)
2024-09-22T14:08:47.png

A,.1fgvw#`/2ehux$~"3dity%_;4cjsz^+{5bkrA&=}6alqB*-[70mpC()]89noX
from regadgets import *
print(decode_b64('$rg7_dhd~Alidg+zeyhz`vnz_d,7sy0=', 'A,.1fgvw#`/2ehux$~"3dity%_;4cjsz^+{5bkrA&=}6alqB*-[70mpC()]89noX'))
# b'BaseCTF{UPX_1s_$o_e@sy}'

好吧,已经解出来了wmmm

[Week2] lk

z3基础题,直接搬运官方wp了(bushi

from z3 import *

a = [Int('a[%d]' % i) for i in range(21)]
s = Solver()
s.add(948 * a[20]
     + 887 * a[19]
     + 410 * a[18]
     + 978 * a[17]
     + 417 * a[16]
     + 908 * a[15]
     + 965 * a[14]
     + 987 * a[13]
     + 141 * a[12]
     + 257 * a[11]
     + 323 * a[10]
     + 931 * a[9]
     + 773 * a[8]
     + 851 * a[7]
     + 758 * a[6]
     + 891 * a[5]
     + 575 * a[4]
     + 616 * a[3]
     + 860 * a[2]
     + 283 * a[1] == 913686)
s.add( 938 * a[20]
     + 490 * a[19]
     + 920 * a[18]
     + 50 * a[17]
     + 568 * a[16]
     + 68 * a[15]
     + 35 * a[14]
     + 708 * a[13]
     + 938 * a[12]
     + 718 * a[11]
     + 589 * a[10]
     + 954 * a[9]
     + 974 * a[8]
     + 62 * a[7]
     + 580 * a[6]
     + 80 * a[5]
     + 111 * a[4]
     + 151 * a[3]
     + 421 * a[2]
     + 148 * a[1] == 630335)
s.add( 908 * a[20]
     + 590 * a[19]
     + 668 * a[18]
     + 222 * a[17]
     + 489 * a[16]
     + 335 * a[15]
     + 778 * a[14]
     + 622 * a[13]
     + 95 * a[12]
     + 920 * a[11]
     + 932 * a[10]
     + 892 * a[9]
     + 409 * a[8]
     + 392 * a[7]
     + 11 * a[6]
     + 113 * a[5]
     + 948 * a[4]
     + 674 * a[3]
     + 506 * a[2]
     + 182 * a[1] == 707525)
s.add( 479 * a[20]
     + 859 * a[19]
     + 410 * a[18]
     + 399 * a[17]
     + 891 * a[16]
     + 266 * a[15]
     + 773 * a[14]
     + 624 * a[13]
     + 34 * a[12]
     + 479 * a[11]
     + 465 * a[10]
     + 728 * a[9]
     + 447 * a[8]
     + 427 * a[7]
     + 890 * a[6]
     + 570 * a[5]
     + 716 * a[4]
     + 180 * a[3]
     + 571 * a[2]
     + 707 * a[1] == 724203)
s.add( 556 * a[20]
     + 798 * a[19]
     + 380 * a[18]
     + 716 * a[17]
     + 71 * a[16]
     + 901 * a[15]
     + 949 * a[14]
     + 304 * a[13]
     + 142 * a[12]
     + 679 * a[11]
     + 459 * a[10]
     + 814 * a[9]
     + 282 * a[8]
     + 49 * a[7]
     + 873 * a[6]
     + 169 * a[5]
     + 437 * a[4]
     + 199 * a[3]
     + 771 * a[2]
     + 807 * a[1] == 688899)
s.add( 465 * a[20]
     + 898 * a[19]
     + 979 * a[18]
     + 198 * a[17]
     + 156 * a[16]
     + 831 * a[15]
     + 856 * a[14]
     + 322 * a[13]
     + 25 * a[12]
     + 35 * a[11]
     + 369 * a[10]
     + 917 * a[9]
     + 522 * a[8]
     + 654 * a[7]
     + 235 * a[6]
     + 385 * a[5]
     + 469 * a[4]
     + 231 * a[3]
     + 496 * a[2]
     + 83 * a[1] == 604784)
s.add( 305 * a[20]
     + 928 * a[19]
     + 260 * a[18]
     + 793 * a[17]
     + 787 * a[16]
     + 708 * a[15]
     + 758 * a[14]
     + 236 * a[13]
     + 688 * a[12]
     + 747 * a[11]
     + 711 * a[10]
     + 195 * a[9]
     + 50 * a[8]
     + 648 * a[7]
     + 787 * a[6]
     + 376 * a[5]
     + 220 * a[4]
     + 33 * a[3]
     + 194 * a[2]
     + 585 * a[1] == 665485)
s.add( 767 * a[20]
     + 573 * a[19]
     + 22 * a[18]
     + 909 * a[17]
     + 598 * a[16]
     + 588 * a[15]
     + 136 * a[14]
     + 848 * a[12]
     + 964 * a[11]
     + 311 * a[10]
     + 701 * a[9]
     + 653 * a[8]
     + 541 * a[7]
     + 443 * a[6]
     + 7 * a[5]
     + 976 * a[4]
     + 803 * a[3]
     + 273 * a[2]
     + 859 * a[1] == 727664)
s.add( 776 * a[20]
     + 59 * a[19]
     + 507 * a[18]
     + 164 * a[17]
     + 397 * a[16]
     + 744 * a[15]
     + 377 * a[14]
     + 768 * a[13]
     + 456 * a[12]
     + 799 * a[11]
     + 9 * a[10]
     + 215 * a[9]
     + 365 * a[8]
     + 181 * a[7]
     + 634 * a[6]
     + 818 * a[5]
     + 81 * a[4]
     + 236 * a[3]
     + 883 * a[2]
     + 95 * a[1] == 572015)
s.add( 873 * a[20]
     + 234 * a[19]
     + 381 * a[18]
     + 423 * a[17]
     + 960 * a[16]
     + 689 * a[15]
     + 617 * a[14]
     + 240 * a[13]
     + 933 * a[12]
     + 300 * a[11]
     + 998 * a[10]
     + 773 * a[9]
     + 484 * a[8]
     + 905 * a[7]
     + 806 * a[6]
     + 792 * a[5]
     + 606 * a[4]
     + 942 * a[3]
     + 422 * a[2]
     + 789 * a[1] == 875498)
s.add( 766 * a[20]
     + 7 * a[19]
     + 283 * a[18]
     + 900 * a[17]
     + 211 * a[16]
     + 305 * a[15]
     + 343 * a[14]
     + 696 * a[13]
     + 590 * a[12]
     + 736 * a[11]
     + 817 * a[10]
     + 603 * a[9]
     + 414 * a[8]
     + 828 * a[7]
     + 114 * a[6]
     + 845 * a[5]
     + 175 * a[4]
     + 212 * a[3]
     + 898 * a[2]
     + 988 * a[1] == 714759)
s.add( 220 * a[20]
     + 30 * a[19]
     + 788 * a[18]
     + 106 * a[17]
     + 574 * a[16]
     + 501 * a[15]
     + 366 * a[14]
     + 952 * a[13]
     + 121 * a[12]
     + 996 * a[11]
     + 735 * a[10]
     + 689 * a[9]
     + 998 * a[8]
     + 689 * a[7]
     + 729 * a[6]
     + 886 * a[5]
     + 860 * a[4]
     + 70 * a[3]
     + 466 * a[2]
     + 961 * a[1] == 778853)
s.add( 313 * a[20]
     + 748 * a[19]
     + 522 * a[18]
     + 864 * a[17]
     + 156 * a[16]
     + 362 * a[15]
     + 283 * a[14]
     + 49 * a[13]
     + 316 * a[12]
     + 79 * a[11]
     + 136 * a[10]
     + 299 * a[9]
     + 271 * a[8]
     + 604 * a[7]
     + 907 * a[6]
     + 540 * a[5]
     + 141 * a[4]
     + 620 * a[3]
     + 701 * a[2]
     + 866 * a[1] == 584591)
s.add( 922 * a[20]
     + 399 * a[19]
     + 425 * a[18]
     + 26 * a[17]
     + 159 * a[16]
     + 224 * a[15]
     + 438 * a[14]
     + 770 * a[13]
     + 144 * a[12]
     + 406 * a[11]
     + 110 * a[10]
     + 991 * a[9]
     + 749 * a[8]
     + 701 * a[7]
     + 646 * a[6]
     + 147 * a[5]
     + 979 * a[4]
     + 674 * a[3]
     + 999 * a[2]
     + 913 * a[1] == 717586)
s.add( 13 * a[20]
     + 537 * a[19]
     + 225 * a[18]
     + 421 * a[17]
     + 153 * a[16]
     + 484 * a[15]
     + 654 * a[14]
     + 743 * a[13]
     + 779 * a[12]
     + 74 * a[11]
     + 325 * a[10]
     + 439 * a[9]
     + 797 * a[8]
     + 41 * a[7]
     + 784 * a[6]
     + 269 * a[5]
     + 454 * a[4]
     + 725 * a[2]
     + 164 * a[1] == 537823)
s.add( 591 * a[20]
     + 210 * a[19]
     + 874 * a[18]
     + 204 * a[17]
     + 485 * a[16]
     + 42 * a[15]
     + 433 * a[14]
     + 176 * a[13]
     + 436 * a[12]
     + 634 * a[11]
     + 82 * a[10]
     + 978 * a[9]
     + 818 * a[8]
     + 683 * a[7]
     + 404 * a[6]
     + 562 * a[5]
     + 41 * a[4]
     + 789 * a[3]
     + 200 * a[2]
     + 220 * a[1] == 587367)
s.add( 584 * a[20]
     + 597 * a[19]
     + 928 * a[18]
     + 532 * a[17]
     + 902 * a[16]
     + 858 * a[15]
     + 820 * a[14]
     + 240 * a[13]
     + 124 * a[12]
     + 899 * a[11]
     + 848 * a[10]
     + 822 * a[9]
     + 409 * a[8]
     + 491 * a[7]
     + 587 * a[6]
     + 715 * a[5]
     + 410 * a[4]
     + 268 * a[3]
     + 721 * a[2]
     + 915 * a[1] == 842245)
s.add( 421 * a[20]
     + 302 * a[19]
     + 327 * a[18]
     + 180 * a[17]
     + a[16] * 512
     + 160 * a[15]
     + 623 * a[14]
     + 28 * a[13]
     + 411 * a[12]
     + 53 * a[11]
     + 633 * a[10]
     + 560 * a[9]
     + 623 * a[8]
     + 477 * a[7]
     + 901 * a[6]
     + 287 * a[5]
     + 149 * a[4]
     + 726 * a[3]
     + 934 * a[2]
     + 875 * a[1] == 610801)
s.add( 838 * a[20]
     + 434 * a[19]
     + 792 * a[18]
     + 649 * a[17]
     + 462 * a[16]
     + 170 * a[15]
     + 980 * a[14]
     + 15 * a[13]
     + 295 * a[12]
     + 495 * a[11]
     + 666 * a[10]
     + 934 * a[9]
     + 17 * a[8]
     + 69 * a[7]
     + 367 * a[6]
     + 780 * a[5]
     + 291 * a[4]
     + 834 * a[3]
     + 587 * a[2]
     + 133 * a[1] == 653127)
s.add( 41 * a[20]
     + 422 * a[19]
     + 420 * a[18]
     + 224 * a[17]
     + 475 * a[16]
     + 854 * a[15]
     + 233 * a[14]
     + 179 * a[13]
     + 620 * a[12]
     + 69 * a[11]
     + 42 * a[10]
     + 684 * a[9]
     + 300 * a[8]
     + 745 * a[7]
     + 894 * a[6]
     + 554 * a[5]
     + 495 * a[4]
     + 66 * a[3]
     + 316 * a[2]
     + 391 * a[1] == 533470 )
if s.check() == sat:
    ans = s.model()
    for i in range(1,21):
        print(chr(ans[a[i]].as_long()), end="")
    #print(s.model())
        
 #CDBBDCAAABBDBCCBCCAC

[Week2] 最简单的编码

2024-09-22T14:16:32.png
动调一下,就能拿到变换后的table

CDABGHEFKLIJOPMNSTQRWXUVabYZefcdijghmnklqropuvstyzwx23016745+/89

然后这是魔改的base64
2024-09-22T14:20:01.png
我是用cpp写的,网上搬的,改了几个偏移,不过年久已丢,此处用官方的

from regadgets import *
table = "CDABGHEFKLIJOPMNSTQRWXUVabYZefcdijghmnklqropuvstyzwx23016745+/89"
enc = "TqK1YUSaQryEMHaLMnWhYU+Fe0WPenqhRXahfkV6WE2fa3iRW197Za62eEaD"
index = []
number = [1,2,3,4]
for i in range(len(enc)):
    tmp = table.index(enc[i]) - number[i % 4]
    if tmp >= 0:
        index.append(tmp)
    else:
        index.append(tmp + 64)
print(index)
for i in range(0,len(index),4):
    sum = index[i] << 18 | index[i + 1] << 12 | index[i + 2] << 6 | index[i + 3]
    for j in range(3):
        print(chr((sum >> ((2 - j) * 8)) & 0xff), end="")
# [16, 38, 5, 51, 25, 20, 13, 20, 17, 39, 45, 2, 13, 3, 21, 5, 13, 35, 17, 31, 25, 20, 57, 3, 27, 52, 17, 9, 27, 35, 37, 31, 18, 19, 21, 31, 28, 36, 20, 52, 19, 4, 49, 25, 23, 51, 29, 15, 19, 53, 60, 53, 26, 22, 53, 48, 27, 4, 21, 61]
# BaseCTF{B45E64_eNCoDIn9_I5_rE4LLY_7OO_5implE}

[Week2] 喝杯下午茶

找key, 找enc,找delta就可以了。

from regadgets import *
k = [0] * 4
k[0] = 287454020
k[1] = 1432778632
k[2] = -1716864052
k[3] = -571539695

v = [0] * 10
v[0] = -1800277529
v[1] = 567661394
v[2] = 1380415805
v[3] = 67968151
v[4] = -210862220
v[5] = -1672218865
v[6] = 1793773528
v[7] = 1872692980
v[8] = -352477650
v[9] = 850810359
v = pack_dword(v)
r = b''
for i in v:
    a, b = tea_decrypt(i, k, 1131796)
    r += l2b(a)[::-1] + l2b(b)[::-1]

print(r)
# b'BaseCTF{h3r3_4_cuP_0f_734_f0R_y0U!!!!!!}'   

[Week2] neuro爱数学

没做,搬一下官方的:
考点是简单的代码审计加代码逻辑仿写
2024-09-22T14:34:48.png
点开IDA发现需要输入9个数
2024-09-22T14:34:55.png
接下来简单分析逻辑
第一段进行了一个简单的运算操作
即计算: $$x_1*i^8+x_2*i^7+x_3*i^6+x_4*i^5+x_5*i^4+x_6*i^3+x_7*i^2+x_8*i^1+x_9*i^0$$
第二段计算(i-44)(i-58)(i-17)(i-6)(i-5)(i+4)(i+9)(i+37)
很多人看不懂,为什么不考虑一下本地模拟呢 or 动调
2024-09-22T14:35:07.png
接下来事情显而易见 将第二段展开,得到的式子和第一段对比即可得到x1-x9
这里用python脚本完成,有能力的同学可以手算。

from sympy import symbols, expand
x = symbols('x')
polynomial = (x - 44) * (x - 58) * (x - 5) * (x + 37) * (x - 17) * (x + 9) * (x - 6) * (x + 4)
expanded_polynomial = expand(polynomial)
standard_form = expanded_polynomial.as_poly()
coefficients = standard_form.all_coeffs()
print(coefficients[::-1])

2024-09-22T14:35:29.png
输入进程序即可得到flag
2024-09-22T14:35:35.png

[Week3] UPX PRO

Linux 的加了upx,而且魔改了一些东西,我们放gdb里面
2024-09-22T14:37:33.png
发现有反调试,我们考虑ptrace反调试
2024-09-22T14:38:01.png
catch syscall ptrace然后s一下(过syscall),再运行
2024-09-22T14:38:24.png
这样我们就能绕过ptrace反调试,然后
2024-09-22T14:38:57.png
就可以绕过反调试,其实在反调试的地方已经过了,我们直接
2024-09-22T14:40:27.png
得到coredump,然后拖入ida
2024-09-22T14:42:41.png
显然我们已经得到了解压后的
随便翻一下,找到个base58,表是
ABCDEFGHJKLMNPQRSTUVWXYZ123456789abcdefghijkmnopqrstuvwxyz
2024-09-22T14:43:37.png
2024-09-22T14:48:32.png

__int64 __fastcall sub_7FFFF7FF9518(__int64 a1, unsigned __int64 a2, __int64 a3, __int64 a4)
{
  _BYTE v5[139]; // [rsp+20h] [rbp-A0h] BYREF
  char v6; // [rsp+ABh] [rbp-15h]
  int v7; // [rsp+ACh] [rbp-14h]
  unsigned __int64 i; // [rsp+B0h] [rbp-10h]
  int v9; // [rsp+B8h] [rbp-8h]
  int v10; // [rsp+BCh] [rbp-4h]

  sub_7FFFF7FF9362(v5, a3, a4);
  v10 = 0;
  v9 = 0;
  v7 = 0;
  for ( i = 0LL; i < a2; ++i )
  {
    v10 = (v10 + 1) % 128;
    v9 = (v9 + (unsigned __int8)v5[v10]) % 128;
    v6 = v5[v10];
    v5[v10] = v5[v9];
    v5[v9] = v6;
    v7 = (v5[v10] + v5[v9]) & 0x7F;
    *(_BYTE *)(a1 + i) ^= v5[v7];
  }
  return 0LL;
}

还有个魔改rc4
稍微还原一下

__int64 __fastcall rc4_init(char *s_box, char *a2, unsigned __int64 len)
{
  char key_box[128]; // [rsp+18h] [rbp-90h] BYREF
  char v5; // [rsp+9Fh] [rbp-9h]
  int v6; // [rsp+A0h] [rbp-8h]
  int i; // [rsp+A4h] [rbp-4h]

  v6 = 0;
  memset(key_box, 0, sizeof(key_box));
  v5 = 0;
  for ( i = 0; i <= 127; ++i )
  {
    s_box[i] = i;
    key_box[i] = key_box[i % len];
  }
  for ( i = 0; i <= 127; ++i )
  {
    v6 = (key_box[i] + v6 + (unsigned __int8)s_box[i]) % 128;
    v5 = s_box[i];                              // swap
    s_box[i] = s_box[v6];
    s_box[v6] = v5;
  }
  return 0LL;
}
__int64 __fastcall rc4_crypt(char *a1, unsigned __int64 a2, char *key, unsigned __int64 key_len)
{
  unsigned __int8 s[128]; // [rsp+20h] [rbp-A0h] BYREF
  unsigned __int8 tmp; // [rsp+ABh] [rbp-15h]
  int v7; // [rsp+ACh] [rbp-14h]
  unsigned __int64 iter; // [rsp+B0h] [rbp-10h]
  int j; // [rsp+B8h] [rbp-8h]
  int i; // [rsp+BCh] [rbp-4h]

  rc4_init((char *)s, key, key_len);
  i = 0;
  j = 0;
  v7 = 0;
  for ( iter = 0LL; iter < a2; ++iter )
  {
    i = (i + 1) % 128;
    j = (j + s[i]) % 128;
    tmp = s[i];                                 // swap
    s[i] = s[j];
    s[j] = tmp;
    v7 = (s[i] + s[j]) & 0x7F;
    a1[iter] ^= s[v7];
  }
  return 0LL;
}

我们发现key根本没用上,rc4的key_box全是0,是空的,可能是出题的时候的一个漏洞。
思路已经很明显了,就是把rc4的sbox空间改成128,就行了。
EXP

from regadgets import *
enc = [0x364A65466C271216, 0x2447243568082139, 0x29323C0F5A1A7D60, 0x4D647C3C45531544, 0x74152339130F7024]
enc = qword2byte(enc)

print(rc4_crypt(rc4_init(b'', 128), enc, 128))
# b'BaseCTF{Rc4_1$_@_G0od_3nCrypt!on_MethOd}'

[Week3] Dont-debug-me

ScyllaHide

[Week4] BaseRE

TLS Callback 和Main里面有花指令
Change base64 table to : HElRNYGmBOMWnbDvUCgcpu1QdPqJIS+iTry39KXse4jLh/x26Ff5Z7Vokt8wzAa0
b64decode('UXY5PpbpCshkP1CrPcU7DlZZSGd5WcO6qRB/D1dfbyZFP3ToncKKd5rXDGCA', my_table);
BaseCTF{8edae458-4tf3-2ph2-9f26-1f8719ec8f8d}

ByteAPK

Flutter rust bridge
ByteCTF{},总长度45
flag被通过ffi传到rust,然后utf8转成c string,去掉了ByteCTF{和后面的},传到一个函数里面check

unsigned char arr1[] =
{
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
  0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
  0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
  0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 
  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 
  0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned int enc[32] = {
    0x0001EE59, 0x0000022A, 0x00001415, 0x00040714, 0x000013E0, 0x000008B8, 0xFFFDCEA0, 0x0000313B, 
    0x0003D798, 0xFFFFFE6B, 0x00000C4E, 0x00023884, 0x0000008D, 0x00001DB4, 0xFFFC1328, 0x00001EAC, 
    0x00043C64, 0x0000142B, 0xFFFFF622, 0x00023941, 0xFFFFEF6D, 0x0000120C, 0xFFFBD30F, 0x00001EBE, 
    0x00045158, 0xFFFFEF66, 0x00001D3F, 0x0004C46B, 0xFFFFF97A, 0x00001BFD, 0xFFFBA235, 0x00001ED2
};

__int64 __fastcall final_enc(unsigned __int8 *flag_intern, __int64 a2)
{
  __int64 v2; // x9
  __int64 v3; // x9
  __int64 v4; // x9
  __int64 v5; // x9
  __int64 v6; // x9
  __int64 v7; // x9
  __int64 v8; // x9
  __int64 v9; // x9
  unsigned int v10; // w11
  int v11; // w13
  __int64 v12; // x9
  __int64 v13; // x9
  __int64 v14; // x9
  __int64 v15; // x9
  __int64 v16; // x9
  unsigned int v18; // w10
  int v19; // w13
  __int64 v20; // x9
  __int64 v21; // x9
  __int64 v22; // x9
  __int64 v23; // x9
  __int64 v24; // x9
  unsigned int v25; // w10
  int v26; // w13
  __int64 v27; // x9
  __int64 v28; // x9
  __int64 v29; // x9
  __int64 v30; // x9
  __int64 v31; // x9
  unsigned int v32; // w8
  int v33; // w11
  unsigned __int64 v34; // x20
  __int64 v35; // x21
  unsigned int v36; // w22
  int v37; // w8
  __int64 v38; // x10
  int v39; // w9
  unsigned __int64 v40; // x8
  __int64 v41; // x9
  unsigned __int64 v42; // x10
  unsigned __int64 v43; // x8
  int v44; // w12
  int v45; // w14
  int v46; // w3
  int v47; // w13
  int v48; // w2
  int v49; // w16
  int v50; // w15
  int v51; // w17
  int v52; // w6
  int v53; // w4
  int v54; // w12
  int *v55; // x13
  __int64 v57; // [xsp+8h] [xbp-48h] BYREF
  __int64 v58; // [xsp+10h] [xbp-40h]
  unsigned __int64 v59; // [xsp+18h] [xbp-38h]

  v57 = 0LL;
  v58 = 4LL;
  if ( a2 != 36 )
    return 0LL;
  v2 = arr1[*flag_intern];
  if ( (_DWORD)v2 == 36 )
    return 0LL;
  v3 = arr1[flag_intern[v2]] + v2;
  if ( v3 == 36 )
    return 0LL;
  v4 = v3 + arr1[flag_intern[v3]];
  if ( v4 == 36 )
    return 0LL;
  v5 = v4 + arr1[flag_intern[v4]];
  if ( v5 == 36 )
    return 0LL;
  v6 = v5 + arr1[flag_intern[v5]];
  if ( v6 == 36 )
    return 0LL;
  v7 = v6 + arr1[flag_intern[v6]];
  if ( v7 == 36 )
    return 0LL;
  v8 = v7 + arr1[flag_intern[v7]];
  if ( v8 == 36 )
    return 0LL;
  v9 = v8 + arr1[flag_intern[v8]];
  if ( v9 == 36 )
    return 0LL;
  v10 = flag_intern[v9];
  if ( (char)flag_intern[v9] < 0 )
  {
    if ( v10 < 0xE0 )
    {
      v10 = flag_intern[v9 + 1] & 0x3F | ((v10 & 0x1F) << 6);
    }
    else
    {
      v11 = flag_intern[v9 + 2] & 0x3F | ((flag_intern[v9 + 1] & 0x3F) << 6);
      if ( v10 < 0xF0 )
        v10 = v11 | ((v10 & 0x1F) << 12);
      else
        v10 = flag_intern[v9 + 3] & 0x3F | (v11 << 6) & 0xFFE3FFFF | ((v10 & 7) << 18);
    }
  }
  if ( v10 != 45 )
    return 0LL;
  v12 = v9 + arr1[flag_intern[v9]];
  if ( v12 == 36 )
    return 0LL;
  v13 = v12 + arr1[flag_intern[v12]];
  if ( v13 == 36 )
    return 0LL;
  v14 = v13 + arr1[flag_intern[v13]];
  if ( v14 == 36 )
    return 0LL;
  v15 = v14 + arr1[flag_intern[v14]];
  if ( v15 == 36 )
    return 0LL;
  v16 = v15 + arr1[flag_intern[v15]];
  if ( v16 == 36 )
    return 0LL;
  v18 = flag_intern[v16];
  if ( (char)flag_intern[v16] < 0 )
  {
    if ( v18 < 0xE0 )
    {
      v18 = flag_intern[v16 + 1] & 0x3F | ((v18 & 0x1F) << 6);
    }
    else
    {
      v19 = flag_intern[v16 + 2] & 0x3F | ((flag_intern[v16 + 1] & 0x3F) << 6);
      if ( v18 < 0xF0 )
        v18 = v19 | ((v18 & 0x1F) << 12);
      else
        v18 = flag_intern[v16 + 3] & 0x3F | (v19 << 6) & 0xFFE3FFFF | ((v18 & 7) << 18);
    }
  }
  if ( v18 != 45 )
    return 0LL;
  v20 = v16 + arr1[flag_intern[v16]];
  if ( v20 == 36 )
    return 0LL;
  v21 = v20 + arr1[flag_intern[v20]];
  if ( v21 == 36 )
    return 0LL;
  v22 = v21 + arr1[flag_intern[v21]];
  if ( v22 == 36 )
    return 0LL;
  v23 = v22 + arr1[flag_intern[v22]];
  if ( v23 == 36 )
    return 0LL;
  v24 = v23 + arr1[flag_intern[v23]];
  if ( v24 == 36 )
    return 0LL;
  v25 = flag_intern[v24];
  if ( (char)flag_intern[v24] < 0 )
  {
    if ( v25 < 0xE0 )
    {
      v25 = flag_intern[v24 + 1] & 0x3F | ((v25 & 0x1F) << 6);
    }
    else
    {
      v26 = flag_intern[v24 + 2] & 0x3F | ((flag_intern[v24 + 1] & 0x3F) << 6);
      if ( v25 < 0xF0 )
        v25 = v26 | ((v25 & 0x1F) << 12);
      else
        v25 = flag_intern[v24 + 3] & 0x3F | (v26 << 6) & 0xFFE3FFFF | ((v25 & 7) << 18);
    }
  }
  if ( v25 != 45 )
    return 0LL;
  v27 = v24 + arr1[flag_intern[v24]];
  if ( v27 == 36 )
    return 0LL;
  v28 = v27 + arr1[flag_intern[v27]];
  if ( v28 == 36 )
    return 0LL;
  v29 = v28 + arr1[flag_intern[v28]];
  if ( v29 == 36 )
    return 0LL;
  v30 = v29 + arr1[flag_intern[v29]];
  if ( v30 == 36 )
    return 0LL;
  v31 = v30 + arr1[flag_intern[v30]];
  if ( v31 == 36 )
    return 0LL;
  v32 = flag_intern[v31];
  if ( (char)flag_intern[v31] < 0 )
  {
    if ( v32 < 0xE0 )
    {
      v32 = flag_intern[v31 + 1] & 0x3F | ((v32 & 0x1F) << 6);
    }
    else
    {
      v33 = flag_intern[v31 + 2] & 0x3F | ((flag_intern[v31 + 1] & 0x3F) << 6);
      if ( v32 < 0xF0 )
        v32 = v33 | ((v32 & 0x1F) << 12);
      else
        v32 = flag_intern[v31 + 3] & 0x3F | (v33 << 6) & 0xFFE3FFFF | ((v32 & 7) << 18);
    }
  }
  if ( v32 != 45 )
    return 0LL;
  v34 = 0LL;
  v35 = 0LL;
  while ( 1 )
  {
    v36 = flag_intern[v35];
    if ( (char)flag_intern[v35] < 0 )
    {
      v37 = flag_intern[v35 + 1] & 0x3F;
      if ( v36 < 0xE0 )
      {
        v35 += 2LL;
        v36 = v37 & 0xFFFFF83F | ((v36 & 0x1F) << 6);
      }
      else
      {
        v38 = v35 + 3;
        v39 = flag_intern[v35 + 2] & 0x3F | (v37 << 6);
        if ( v36 < 0xF0 )
        {
          v36 = v39 | ((v36 & 0x1F) << 12);
          v35 += 3LL;
        }
        else
        {
          v35 += 4LL;
          v36 = flag_intern[v38] & 0x3F | (v39 << 6) & 0xFFE3FFFF | ((v36 & 7) << 18);
        }
      }
    }
    else
    {
      ++v35;
    }
    if ( v36 != 45 )
      break;
LABEL_55:
    if ( v35 == 36 )
      goto LABEL_67;
  }
  if ( v36 != 0x110000 )
  {
    if ( v34 == v57 )
      sub_3B688(&v57, a2);
    *(_DWORD *)(v58 + 4 * v34++) = v36;
    v59 = v34;
    goto LABEL_55;
  }
LABEL_67:
  v40 = v34 >> 3;
  v41 = 0LL;
  if ( (v34 & 7) != 0 )
    ++v40;
  v42 = v40 + 1;
  v43 = 8LL;
  while ( --v42 )
  {
    if ( v43 > v34 )
      goto LABEL_88;
    if ( v43 - 8 >= 0x19 )
    {
      v43 = 40LL;
      v34 = 32LL;
LABEL_88:
      panic(v43, v34, (__int64)&off_801E0);
    }
    v45 = *(_DWORD *)(v58 + v41 * 4 + 8);
    v44 = *(_DWORD *)(v58 + v41 * 4 + 12);
    v46 = *(_DWORD *)(v58 + v41 * 4);
    v47 = *(_DWORD *)(v58 + v41 * 4 + 4);
    v48 = *(_DWORD *)(v58 + v41 * 4 + 16);
    v49 = *(_DWORD *)(v58 + v41 * 4 + 20);
    v50 = *(_DWORD *)(v58 + v41 * 4 + 24);
    v51 = *(_DWORD *)(v58 + v41 * 4 + 28);
    if ( v51 + v47 * v44 * v49 - (v46 + v50 + v45 * v48) == enc[v41] )
    {
      v52 = v46 * v49;
      if ( v44 - v48 - v46 * v49 + v51 * v47 + v45 + v50 == enc[v41 + 1]
        && v52 - (v48 + v51 * v47) + v45 + v50 * v44 == enc[v41 + 2] )
      {
        v53 = v48 * v46;
        if ( v47 + v48 * v46 - (v51 + v45) + v50 * v49 * v44 == enc[v41 + 3]
          && v49 * v44 + v47 + v45 * v48 - (v50 + v51 * v46) == enc[v41 + 4]
          && v52 + v47 * v44 + v45 - (v50 + v48 * v51) == enc[v41 + 5]
          && v51 - v47 + v45 * v49 + v50 - v53 * v44 == enc[v41 + 6] )
        {
          v43 += 8LL;
          v54 = v44 - v51 - (v47 + v49);
          v55 = &enc[v41];
          v41 += 8LL;
          if ( v54 + v53 + v50 * v45 == v55[7] )
            continue;
        }
      }
    }
    if ( v57 )
      c_free(v58, 4 * v57, 4LL);
    return 0LL;
  }
  if ( v57 )
    c_free(v58, 4 * v57, 4LL);
  return 1LL;
}

通过观察,注意到前面的一堆是在检验是否是UUID,后面则是一个标准的z3题目。
exp

from regadgets import *
from z3 import *

enc = [
    0x0001EE59, 0x0000022A, 0x00001415, 0x00040714, 0x000013E0, 0x000008B8, 0xFFFDCEA0, 0x0000313B, 
    0x0003D798, 0xFFFFFE6B, 0x00000C4E, 0x00023884, 0x0000008D, 0x00001DB4, 0xFFFC1328, 0x00001EAC, 
    0x00043C64, 0x0000142B, 0xFFFFF622, 0x00023941, 0xFFFFEF6D, 0x0000120C, 0xFFFBD30F, 0x00001EBE, 
    0x00045158, 0xFFFFEF66, 0x00001D3F, 0x0004C46B, 0xFFFFF97A, 0x00001BFD, 0xFFFBA235, 0x00001ED2
]

for j in range(4):
    x = [BitVec(f"x{i+1}", 32) for i in range(8)]
    x1, x2, x3, x4, x5, x6, x7, x8 = tuple(i for i in x)
    s = Solver()
    for i in x:
        s.add(i > 0x20, i < 0x80)
    s.add(x8 + x2 * x4 * x6 - (x1 + x7 + x3 * x5) == enc[0+j*8])
    v52 = x1 * x6
    s.add(x4 - x5 - x1 * x6 + x8 * x2 + x3 + x7 == enc[1+j*8])
    s.add(v52 - (x5 + x8 * x2) + x3 + x7 * x4 == enc[2+j*8])
    v53 = x5 * x1
    s.add(x2 + x5 * x1 - (x8 + x3) + x7 * x6 * x4 == enc[3+j*8])
    s.add(x6 * x4 + x2 + x3 * x5 - (x7 + x8 * x1) == enc[4+j*8])
    s.add(v52 + x2 * x4 + x3 - (x7 + x5 * x8) == enc[5+j*8])
    s.add(x8 - x2 + x3 * x6 + x7 - v53 * x4 == enc[6+j*8])
    v54 = x4 - x8 - (x2 + x6)
    s.add(v54 + v53 + x7 * x3 == enc[7+j*8])
    
    if s.check() == sat:
        m = s.model()
        for i in x:
            l = m[i].as_long()
            print(l2b(l).decode(),end='')
            # 32e750c8fb214562af22973fb5176b9c
            # ByteCTF{32e750c8-fb21-4562-af22-973fb5176b9c}

x64_extension

AES-256 密钥扩增魔改
2024-09-20T16:26:55.png
2024-09-20T16:26:31.png

from regadgets import *
k = bytes([0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f])
iv = bytes([0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0])
a = AES(k)
data = open('flag.txt.enc', 'rb').read()
print(a.decrypt_cbc(data, iv))
# b"Hey Sekai CTF Player, I hope you are fine and are enjoying the CTF. Keep going, here is your reward! The flag is SEKAI{Pl34Se_It'5_jUs7_@_wAaaarmUp}\n"

SEKAI{Pl34Se_It'5_jUs7_@_wAaaarmUp}

迷宫

逆天题目,答案直接给你了。

FindTheKey

.so的JNI_OnLoad中,最后调用了sub_B004(前面都是frida检测),疑似是某个加固软件的,见了很多次。

int __fastcall sub_B004(JNIEnv *a1)
{
  jobject v2; // [sp+38h] [bp-E8h]
  jobject v3; // [sp+3Ch] [bp-E4h]
  jsize j; // [sp+40h] [bp-E0h]
  jobject ObjectArrayElement; // [sp+44h] [bp-DCh]
  jsize i; // [sp+48h] [bp-D8h]
  jobject v7; // [sp+4Ch] [bp-D4h]
  struct _jmethodID *v8; // [sp+50h] [bp-D0h]
  struct _jmethodID *v9; // [sp+54h] [bp-CCh]
  struct _jmethodID *v10; // [sp+58h] [bp-C8h]
  jclass v11; // [sp+5Ch] [bp-C4h]
  jobject v12; // [sp+60h] [bp-C0h]
  jobject v13; // [sp+64h] [bp-BCh]
  jobject v14; // [sp+68h] [bp-B8h]
  jobject v15; // [sp+6Ch] [bp-B4h]
  jobject v16; // [sp+70h] [bp-B0h]
  struct _jmethodID *v17; // [sp+74h] [bp-ACh]
  jclass v18; // [sp+78h] [bp-A8h]
  struct _jfieldID *v19; // [sp+7Ch] [bp-A4h]
  jclass v20; // [sp+80h] [bp-A0h]
  struct _jfieldID *v21; // [sp+84h] [bp-9Ch]
  jclass v22; // [sp+88h] [bp-98h]
  jobject clazz_loader; // [sp+8Ch] [bp-94h]
  struct _jmethodID *v24; // [sp+90h] [bp-90h]
  jclass v25; // [sp+94h] [bp-8Ch]
  jclass main_activity; // [sp+98h] [bp-88h]
  struct _jmethodID *v27; // [sp+9Ch] [bp-84h]
  struct _jmethodID *v28; // [sp+A0h] [bp-80h]
  void *v29; // [sp+A4h] [bp-7Ch]
  jmethodID StaticMethodID; // [sp+A8h] [bp-78h]
  jclass v31; // [sp+ACh] [bp-74h]
  void *ptr; // [sp+B4h] [bp-6Ch]
  void *v33; // [sp+B8h] [bp-68h]
  jint v34; // [sp+BCh] [bp-64h]
  struct _jmethodID *read__; // [sp+C0h] [bp-60h]
  jclass v36; // [sp+C4h] [bp-5Ch]
  jbyteArray _array_; // [sp+C8h] [bp-58h]
  jobject v38; // [sp+CCh] [bp-54h]
  struct _jmethodID *v39; // [sp+D0h] [bp-50h]
  size_t size; // [sp+D4h] [bp-4Ch]
  struct _jmethodID *v41; // [sp+D8h] [bp-48h]
  jclass v42; // [sp+DCh] [bp-44h]
  jobject v43; // [sp+E0h] [bp-40h]
  jstring v44; // [sp+E4h] [bp-3Ch]
  struct _jmethodID *v45; // [sp+ECh] [bp-34h]
  jclass v46; // [sp+F0h] [bp-30h]
  jobject v47; // [sp+F4h] [bp-2Ch]
  struct _jmethodID *MethodID; // [sp+F8h] [bp-28h]
  jclass v49; // [sp+FCh] [bp-24h]
  jobject ObjectField; // [sp+100h] [bp-20h]
  jobject StaticObjectField; // [sp+104h] [bp-1Ch]
  struct _jfieldID *FieldID; // [sp+108h] [bp-18h]
  struct _jfieldID *StaticFieldID; // [sp+10Ch] [bp-14h]
  jclass Class; // [sp+110h] [bp-10h]

  Class = FindClass(a1, asc_1F0A0);             // android/app/ActivityThread
  StaticFieldID = GetStaticFieldID(a1, Class, aWgqvvajpegpmrm, aDiflzgalIxxIkA);
  FieldID = GetFieldID(a1, Class, byte_1F280, byte_1F2A0);
  StaticObjectField = GetStaticObjectField(a1, Class, StaticFieldID);
  ObjectField = GetObjectField(a1, StaticObjectField, FieldID);
  v49 = FindClass(a1, aTHus5Jj5JjvsyN);         // android/app/Application
  MethodID = GetMethodID(a1, v49, byte_1F2D8, byte_1F2F0);
  v47 = CallObjectMethodV(a1, ObjectField, MethodID);
  v46 = FindClass(a1, byte_1F320);              // android/content/res/AssetManager
  v45 = GetMethodID(a1, v46, byte_1F341, byte_1F350);
  v44 = NewStringUTF(a1, aOKzLg);               // asset.bin
  v43 = CallObjectMethodV(a1, v47, v45, v44);
  v42 = FindClass(a1, aFicuhncDhisbis);         // android/content/res/AssetFileDescriptor
  v41 = GetMethodID(a1, v42, byte_1F3C8, byte_1F3D2);// getLength
  size = CallLongMethodV(a1, v43, v41);
  v39 = GetMethodID(a1, v46, "7(=6X", byte_1F3E0);// open
  v38 = CallObjectMethodV(a1, v47, v39, v44);
  _array_ = NewByteArray(a1, size);
  v36 = FindClass(a1, byte_1F410);              // java/io/InputStream
  read__ = GetMethodID(a1, v36, aRead, byte_1F429);// read ([BII)I
  v34 = CallIntMethodV(a1, v38, read__, _array_, 0, size);
  v33 = malloc(size);
  if ( v34 >= 1 )
    GetByteArrayRegion(a1, (int)_array_, 0, size, (int)v33);
  ptr = malloc(size);
  sub_AC38(unk_1F431, v33, size, ptr);          // RC4(goodluck)
  SetByteArrayRegion(a1, (int)_array_, 0, size, (int)ptr);
  if ( ptr )
    free(ptr);
  if ( v33 )
    free(v33);
  v31 = FindClass(a1, byte_1F440);
  StaticMethodID = GetStaticMethodID(a1, v31, byte_1F454, byte_1F460);
  v29 = (void *)sub_A234(a1, v31, StaticMethodID, size);
  v28 = GetMethodID(a1, v31, byte_1F479, byte_1F480);// put ([B)Ljava/nio/ByteBuffer;
  v27 = GetMethodID(a1, v31, byte_1F49A, byte_1F4B0);// position (I)Ljava/nio/Buffer;
  CallObjectMethodV(a1, v29, v28, _array_);
  CallObjectMethodV(a1, v29, v27, 0);
  main_activity = FindClass(a1, byte_1F4D0);    // com/ctf/findthekey/MainActivity
  v25 = FindClass(a1, a388v587V);               // java/lang/Class
                                                // 
  v24 = GetMethodID(a1, v25, byte_1F500, byte_1F510);// getClassLoader
  clazz_loader = CallObjectMethodV(a1, main_activity, v24);
  v22 = FindClass(a1, byte_1F530);
  v21 = GetFieldID(a1, v22, byte_1F54E, aVVlsq5icin);// pathList Ldalvik/system/DexPathList;
  v20 = FindClass(a1, byte_1F580);              // dalvik/system/DexPathList
  v19 = GetFieldID(a1, v20, ":;&\x1B2;3;0*-^", byte_1F5B0);// dexElements [Ldalvik/system/DexPathList$Element;
  v18 = FindClass(a1, byte_1F5E0);              // dalvik/system/InMemoryDexClassLoader
  v17 = GetMethodID(a1, v18, "k>9>#iW", byte_1F610);
  v16 = NewObjectV(a1, v18, v17, v29, clazz_loader);
  v15 = GetObjectField(a1, v16, v21);
  v14 = GetObjectField(a1, v15, v19);
  v13 = GetObjectField(a1, clazz_loader, v21);
  v12 = GetObjectField(a1, v13, v19);
  v11 = FindClass(a1, byte_1F640);              // java/util/ArrayList
  v10 = GetMethodID(a1, v11, aJoo, byte_1F660);
  v9 = GetMethodID(a1, v11, aCxveevn7, byte_1F680);
  v8 = GetMethodID(a1, v11, "k>9>#iW", byte_1F696);
  v7 = NewObjectV(a1, v11, v8);
  for ( i = 0; i < GetArrayLength(a1, v14); ++i )
  {
    ObjectArrayElement = GetObjectArrayElement(a1, v14, i);
    CallBooleanMethodV(a1, v7, v10, ObjectArrayElement);
  }
  for ( j = 0; j < GetArrayLength(a1, v12); ++j )
  {
    v3 = GetObjectArrayElement(a1, v12, j);
    CallBooleanMethodV(a1, v7, v10, v3);
  }
  v2 = CallObjectMethodV(a1, v7, v9);
  return SetObjectField(a1, (int)v13, (int)v19, (int)v2);
}

显然是读取了Assets的asset.bin,然后走rc4解密

int __fastcall sub_AC38(const char *k, char *key, unsigned int len, char *buf)
{
  char S[256]; // [sp+34h] [bp-114h] BYREF

  rc4_init(k, S);
  rc4_crypt(S, key, buf, len);
  return 0;
}
int __fastcall rc4_init(const char *k, const char *S)
{
  int j; // [sp+18h] [bp-20h]
  int i; // [sp+1Ch] [bp-1Ch]
  int v5; // [sp+20h] [bp-18h]
  signed int v6; // [sp+24h] [bp-14h]

  v6 = strlen(k);
  v5 = 0;
  for ( i = 0; i <= 255; ++i )
    S[i] = i;
  for ( j = 0; j <= 255; ++j )
  {
    v5 = ((unsigned __int8)k[j % v6] + v5 + (unsigned __int8)S[j]) % 256;
    swap(&S[j], &S[v5]);
  }
  return 0;
}
int __fastcall rc4_crypt(char *S, char *a2, char *dest, unsigned int len)
{
  unsigned int i; // [sp+1Ch] [bp-24h]
  int v6; // [sp+20h] [bp-20h]
  int v7; // [sp+24h] [bp-1Ch]

  v7 = 0;
  v6 = 0;
  for ( i = 0; i < len; ++i )
  {
    v7 = (v7 + 1) % 256;
    v6 = (v6 + (unsigned __int8)S[v7]) % 256;
    swap(&S[v7], &S[v6]);
    dest[i] = S[(unsigned __int8)(S[v7] + S[v6])] ^ a2[i];
  }
  return 0;
}
int __fastcall swap(_BYTE *a1, _BYTE *a2)
{
  int result; // r0
  int v3; // [sp+8h] [bp-Ch]

  v3 = (unsigned __int8)*a1;
  *a1 = *a2;
  result = v3;
  *a2 = v3;
  return result;
}

然后解密了asset.bin就可以直接拖入jadx了
2024-09-18T09:07:20.png
覆盖Util.java,换表base64+rc4,就可以CyberChef解了。

z3 获取所有解

from z3 import *

def get_models(s, count = 1):
    result = []
    while len(result) < count and s.check() == sat:
        m = s.model()
        result.append(m)
        # Create a new constraint the blocks the current model
        block = []
        for d in m:
            # d is a declaration
            if d.arity() > 0:
                raise Z3Exception("uninterpreted functions are not supported")
            # create a constant from declaration
            c = d()
            if is_array(c) or c.sort().kind() == Z3_UNINTERPRETED_SORT:
                raise Z3Exception("arrays and uninterpreted sorts are not supported")
            block.append(c != m[d])
        s.add(Or(block))
    return result

x, y = Ints('x y')
s = Solver()
s.add(And(And(x > 0, y > 0), x * y < 10))
m = get_models(s, 1000) # 获取最多1000个解
print(m)
# [[x = 8, y = 1], [x = 1, y = 2], [x = 2, y = 1], [x = 9, y = 1], [x = 4, y = 2], [x = 3, y = 2], [x = 2, y = 2], [x = 1, y = 3], [x = 1, y = 4], [x = 1, y = 5], [x = 1, y = 6], [x = 1, y = 7], [x = 1, y = 8], [x = 1, y = 9], [x = 2, y = 4], [x = 3, y = 3], [x = 5, y = 1], [x = 6, y = 1], [x = 7, y = 1], [x = 4, y = 1], [x = 3, y = 1], [x = 2, y = 3], [x = 1, y = 1]]