分类 WriteUps 下的文章

Reverse

Simple_encryption

enc = list(bytes.fromhex("47953448A41C358864168807146A3912A20A375C075A5660127625128E28"))
for i in range(len(enc)):
    if i % 3 == 2:
        enc[i] ^= 0x55
    if i % 3 == 1:
        enc[i] -= 41
    if i % 3 == 0:
        enc[i] += 31

print(bytes(enc))

ez_debug

调试后直接把enc抄出来,用CyberChef xor 0x17然后再xor_cycle ATRI
flag{y0u_ar3_g0od_@_Debu9}

ezAndroidStudy

按照题目里面的提示慢慢找就行,很有趣的一个题。

drink_TEA

标准TEA,找到key和delta即可。

Ptrace

father程序的这里修改了son程序进行ROR8的参数(4->3),我是直接全部都爆破了一遍,就看到3解出来了。
2024-10-06T18:07:50.png
顺便:
2024-10-07T09:22:07.png

ezencrypt

android题,native里面有个rc4和xor,然后可以解密出来base64(aes加密后的),然后在java里面找decrypt,开一个idea,然后运行一下就秒了。

PangBai 泰拉记(1)

密文异或了两部分,有个反调试,不看反调试检测出来后的逻辑(看下面的else for)

Dirty_flowers

直接看汇编,循环异或dirty_flower,然后随便翻一下找到密文对比
2024-10-06T18:11:42.png
抄出来解密就行

后面没写了,找个时间补上

ez_rust

x64dbg开调,搜that's,找到一块
spatchEvent(new Event("input")))}const ln=Symbol("_assign"),zi={created(e,{modifiers:{lazy:t,trim:n,number:s}},r){e[ln]=ws(r);const o=s||r.props&&r.props.type==="number";We(e,t?"change":"input",i=>{if(i.target.composing)return;let c=e.value;n&&(c=c.trim()),o&&(c=cn(c)),e[ln](c)}),n&&We(e,"change",()=>{e.value=e.value.trim()}),t||(We(e,"compositionstart",qi),We(e,"compositionend",Cs),We(e,"change",Cs))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,modifiers:{lazy:n,trim:s,number:r}},o){if(e[ln]=ws(o),e.composing)return;const i=r||e.type==="number"?cn(e.value):e.value,c=t??"";i!==c&&(document.activeElement===e&&e.type!=="range"&&(n||s&&e.value.trim()===c)||(e.value=c))}},Ji=["ctrl","shift","alt","meta"],Yi={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>Ji.some(n=>e[`${n}Key`]&&!t.includes(n))},Qi=(e,t)=>{const n=e._withMods||(e._withMods={}),s=t.join(".");return n[s]||(n[s]=(r,...o)=>{for(let i=0;i<t.length;i++){const c=Yi[t[i]];if(c&&c(r,t))return}return e(r,...o)})},Xi=Y({patchProp:Wi},Ii);let Os;function Zi(){return Os||(Os=ri(Xi))}const ki=(...e)=>{const t=Zi().createApp(...e),{mount:n}=t;return t.mount=s=>{const r=tl(s);if(!r)return;const o=t._component;!A(o)&&!o.render&&!o.template&&(o.template=r.innerHTML),r.innerHTML="";const i=n(r,!1,el(r));return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),i},t};function el(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function tl(e){return z(e)?document.querySelector(e):e}const nl=ve("button",{type:"submit"},"go!",-1),sl={__name:"Greet",setup(e){const t=ts(""),n=ts("");function s(o,i="secret"){for(var c="",u=i.length,d=0;d<o.length;d++){var h=o.charCodeAt(d),x=i.charCodeAt(d%u),w=h^x;c+=String.fromCharCode(w)}return c}async function r(){if(n.value===""){t.value="Please enter a name.";return}btoa(s(n.value))==="JFYvMVU5QDoNQjomJlBULSQaCihTAFY="?t.value="Great, you got the flag!":t.value="No, that's not my name."}return(o,i)=>(mr(),br(ge,null,[ve("form",{class:"row",onSubmit:Qi(r,["prevent"])},[Mo(ve("input",{id:"greet-input","onUpdate:modelValue":i[0]||(i[0]=c=>n.value=c),placeholder:"Enter a name..."},null,512),[[zi,n.value]]),nl],32),ve("p",null,Nr(t.value),1)],64))}},rl=(e,t)=>{const n=e.__vccOpts||e;for(const[s,r]of t)n[s]=r;return n},Kn=e=>(bo("data-v-bacdabd6"),e=e(),yo(),e),ol={class:"container"},il=Kn(()=>ve("h1",null,"Welcome to L3HCTF!",-1)),ll=Kn(()=>ve("p",null,"Hope you have a good time playing.",-1)),cl=Kn(()=>ve("p",null,"Now please tell me a name.",-1)),fl={__name:"App",setup(e){return(t,n)=>(mr(),br("div",ol,[il,ll,cl,Ae(sl)]))}},ul=rl(fl,[["__scopeId","data-v-bacdabd6"]]);ki(ul).mount("#app");
分析可知,"JFYvMVU5QDoNQjomJlBULSQaCihTAFY=" == base64_encode(bxor_cycle(input,b'secret'))
L3HCTF{W3LC0M3_n0_RU57_AnyM0r3}

babycom

x64dbg附加,注意到中途主程序会往外写一个com(从资源里面读取)。
注意到是babycom.dll,我们直接断输入的字符串,发现进去后是一个xtea
xtea参数:
key=EA 3E D4 1C 70 CB D7 47 98 5E CA DB 53 0C 39 2B
delta=0x114514
round=32
然后经过对比发现是一个标准的。
2024-09-25T09:52:54.png
继续往下分析,xtea之后还有一个加密。
用了一个Bcrypt的加密,调API就可以解密。

#include <iostream>
#include <Windows.h>
int main()
{
    HCRYPTPROV phProv;
    HCRYPTHASH phHash;
    HCRYPTKEY phKey;
    const BYTE key[] = {
        0xEA, 0x3E, 0xD4, 0x1C, 0x70, 0xCB, 0xD7, 0x47, 0x98, 0x5E, 0xCA, 0xDB, 0x53, 0x0C, 0x39, 0x2B
    };

    const BYTE MultiByteStr[] = {0xb, 0xaf, 0x51, 0x21, 0x9c, 0x52, 0x10, 0x89,
                    0x3f, 0x2c, 0x34, 0x30, 0x87, 0x13, 0xc1, 0x4c,
                    0xc1, 0x7f, 0x81, 0x6e, 0xba, 0xbd, 0xdf, 0x43,
                    0x1a, 0xf0, 0xd7, 0xde, 0x8e, 0x66, 0xb9, 0x7c };
    DWORD pdwDataLen = 32;
    if (CryptAcquireContextA(&phProv, 0LL, 0LL, 0x18u, 0xF0000000)
        && CryptCreateHash(phProv, 32771u, 0LL, 0, &phHash)
        && CryptHashData(phHash, key, 0x10u, 0)
        && CryptDeriveKey(phProv, 0x660Eu, phHash, 1u, &phKey))
    {
        CryptDecrypt(phKey, 0LL, 0, 0, (BYTE*)MultiByteStr, &pdwDataLen);
    }
    return 0;
/* Decrypted
2a b4 c1 74 d6 59 aa 05 73 10 7f 9c 40 49 99 62
3c 84 51 8f 3f 37 ab f1 0e fe 61 96 45 ad 41 6a
*/
}

综上所述

from regadgets import *
encc = pack_dword(byte2dword(bytes.fromhex("""
2a b4 c1 74 d6 59 aa 05 73 10 7f 9c 40 49 99 62
3c 84 51 8f 3f 37 ab f1 0e fe 61 96 45 ad 41 6a
""")))
key = byte2dword(b"\xEA\x3E\xD4\x1C\x70\xCB\xD7\x47\x98\x5E\xCA\xDB\x53\x0C\x39\x2B")
r = b''
for i in encc:
    result = xtea_decrypt(i, key, delta=0x114514, rounds=32)
    r += dword2byte(list(result))
print(r)
# L3HCTF{C0M_Th3C0d3_1s_FuN!!!!!!}

丢一个Ctypes版本的(纯python解决)

from regadgets import *
from ctypes import *
lib_advapi32 = windll.LoadLibrary('advapi32.dll')
pfunc_CryptAcquireContextA = lib_advapi32.CryptAcquireContextA
pfunc_CryptCreateHash = lib_advapi32.CryptCreateHash
pfunc_CryptHashData = lib_advapi32.CryptHashData
pfunc_CryptDeriveKey = lib_advapi32.CryptDeriveKey
pfunc_CryptDecrypt = lib_advapi32.CryptDecrypt
phProv = c_uint64(0)
phHash = c_uint64(0)
phKey = c_uint64(0)
pdwDataLen = c_uint32(32)
if pfunc_CryptAcquireContextA(pointer(phProv), 0, 0, 0x18, 0xF0000000) == 0:
    print("failed 0")
    exit(0)
if pfunc_CryptCreateHash(phProv, 32771, 0, 0, pointer(phHash)) == 0:
    print("failed 1")
    exit(0)
key = b"\xEA\x3E\xD4\x1C\x70\xCB\xD7\x47\x98\x5E\xCA\xDB\x53\x0C\x39\x2B"
if pfunc_CryptHashData(phHash, create_string_buffer(key), 0x10, 0) == 0:
    print("failed 2")
    exit(0)
if pfunc_CryptDeriveKey(phProv, 0x660E, phHash, 1, pointer(phKey)) == 0:
    print("failed 3")
    exit(0)

correct = b"\x0B\xAF\x51\x21\x9C\x52\x10\x89\x3F\x2C\x34\x30\x87\x13\xC1\x4C\xC1\x7F\x81\x6E\xBA\xBD\xDF\x43\x1A\xF0\xD7\xDE\x8E\x66\xB9\x7C"
buf = create_string_buffer(correct)
pfunc_CryptDecrypt(phKey, 0, 0, 0, buf, pointer(pdwDataLen))

encc = pack_dword(byte2dword(buf.raw), padding=True)
r = b''
for i in encc:
    result = xtea_decrypt(i, byte2dword(key), delta=0x114514, rounds=32)
    r += dword2byte(list(result))
print(r)

# b'L3HCTF{C0M_Th3C0d3_1s_FuN!!!!!!}\xa0\xbf\xbc\xcf>\xb1\x194'

[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}