[MoeCTF 2021]地狱通讯

Posted kode00

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[MoeCTF 2021]地狱通讯相关的知识,希望对你有一定的参考价值。

[MoeCTF 2021]地狱通讯

首先看题:

from flask import Flask, render_template, request
from flag import flag, FLAG   //这里flag是一个全局变量
import datetime

app = Flask(__name__)


@app.route("/", methods=[\'GET\', \'POST\'])
def index():
    f = open("app.py", "r")
    ctx = f.read()
    f.close()
    f1ag = request.args.get(\'f1ag\') or ""
    exp = request.args.get(\'exp\') or ""
    flAg = FLAG(f1ag)
    message = "Your flag is 0" + exp
    if exp == "":
        return ctx
    else:
        return message.format(flAg)


if __name__ == "__main__":
    app.run()

首先看代码get请求传入f1ag和exp并且将f1ag传入FLAG函数里面,并且将FLAG的返回值f1Ag与exp拼接存在message变量里,如果exp存在值的话就返回拼接后的字符串。

我们知道format会把f1Ag的值带入到变量message"Your flag is 0"中的0,所以我们让exp中也有一个0,这样就可以将f1Ag中的值代入进去,然后找到他的所属类,然后找到FLAG中的全局变量flag。与下图所示类似:

 payload:?f1ag=1&exp=0.__class__.__init__.__globals__        //这里注意必须是0才可以,因为只有一个f1Ag的值往进传,所以前后必须是一样的,如果为其他数字的话需要俩个变量往进传。

参考文章:https://yanluow.github.io/2020/02/29/python%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%A0%94%E7%A9%B6/#Flask%E4%B8%8B%E8%AF%BB%E5%8F%96secret-key

 

2020moectf—flower

flower

题目:moectf Re flower

运行程序,看程序是如何运作的,发现给了一首诗,还抛出了一个经典的不能在经典的一个问题。然后输入任意字符串,emm竟然被教育了一顿。
但看它的报错是提示我们输入的字符串太长,因此输入一个短的,看来这阅卷老师是真厉害,直接把我高中的底给透出来了。

直接奖励它给他拖入ida中,查找程序出现的字符串,发现了一处让人一看就兴奋的字符串。


直接查看它在代码段中的位置,并使用F5插件得到主函数的伪代码,通过分析,前面一串伪代码是判断你输入的长度,如果不等于16的话程序就会退出,并输出一句话。


我们先查看off_4032A4函数,发现在它的地址上声明了两个函数,第一个函数就先命名为Swapposition,第二个函数就命名为encryption


我们先看第一个Swapposition函数,发现它并不能被ida转化为伪代码,但可以看到在红色位置出现明显错误,又因首字节是E8,猜测很有可能是为了防止反汇编而添加的一个字节,因此将其首字节E8patch为90(nop),并创建函数就可以转化成伪代码了。

分析汇编指令和伪代码,是先将Str2[result] xor(异或)16,然后将异或后的结果传给寄存器dl,然后将cl向左移动四位,再将dl向右移动四位,最后在进行or(或)运算相加。由于cl,dl寄存器只能存储两个16进制,因此在向左移动四位时相当于16进制数向左移动一位,并舍弃最左边的16进制,右边补0;向右移动时舍弃最右边的一位,左边补0。最后的结果就是将两个16进制位置互换了一下。


接着分析第二个函数,发现在代码段有一串数据,这是因为ida是递归分析的,当分析到jmp这个无条件跳转命令时,jmp所跳过的区域ida是不会进行反汇编的。但OD并不是递归分析,而是线性分析,它是逐条指令依次向下分析。

F5转化成伪代码,查看off_404018,发现有三个函数,分别命名为sub,xor,abs函数。for循环的作用就是依次调用这三个函数,并传递两个参数。


先看第一个函数sub,又是相同的问题,直接将E8patch成90,然后创建函数F5(后面两个函数也是如此)。发现他是将 我们的输入与参数a2相加。

第二个函数xor

第三个函数abs,这就有点意思了,abs()是取绝对值的意思,但通过X32debug动态分析后发现,并不是我们想象中的取法。


现在来动态调试看一下这个取绝对值的过程是咋样的。同意我们先通过字符串找到主函数在哪,并按 F2 设置断点,然后运行。输入长度为16的字符串,程序运行到断点处。步过函数,因为要分析第二个encryption函数,知道第二次到达call eax处然后进入此函数。


在这里原本是要跳过两次call ecx但在步过的时候直接跳到了其他地方,并且不能在调试了,猜测函数里有反调试的东西,于是在第一次就直接进入函数,发现这处与ida的所反汇编出来的代码不一样,在ida中是8b 45 0c因此修改X32中的90为8b,这样第一个函数sub就修改完成了(后面两个函数也是如此)。


修改完后,查看第三个函数abs的取值过程,将数据段中的37给了寄存器eax,将77给了ecx,然后神奇的一步就来了,当sub eax,ecx时,eax的值变为了0xFFFFFFc0。接着执行cdq后edx值变为0xFFFFFFFF,然后xor eax,edx sub eax,edx得到37-77后的绝对值。对于相减后结果大于0的情况cdq后edx值变为0。弄清取绝对值的过程后,编写脚本就方便了。



回到ida中的encryption函数,在for循环结束后,又调用了递归函数,

因为传入的参数dword_404390是定值65,且与我们输入的字符串无关,且并不知道dword_404394的值,因此在这可以用动态调试查看这个函数是如何运行的。
继续之前的动态调试,进入函数,这时一定要一直点步进,并且每当执行到mov byte ptr ds:[ecx+54398],al时,要记录一下al的值。

在执行到这一步时,在点步进没有反应,因为这时候*ds:[esi]*的地址调试器没有找到,所以就没有这个值,默认不存在,需要手动跳出。



继续点步进,直至跳出digui函数,发现记录了15个数据,并且Str的前15个数据分别与记录的15个数据进行xor(异或)操作。
最后用Str2与byte_4032AC比较,相同即原来输入的字符串套上moectf就为flag。程序的逻辑分析到这就结束了,接下来编写脚本。
由于本人能力不足(惭愧),在解密abs函数时,并不知道Str[a1] (key1[a1])Str[a2] (key1[a2]) 谁大谁小,就采用了最笨的方法将Str[a1] 可能的两个值都解出来,再代入检验,才将flag解出来。

key='3EFE99768BDC0D1832786FBF43743373'#最后对比的值
key1=[int (a,16) for a in [key[i:i+2] for i in range(0,len(key),2)]]
key3='4d4c47504b46434a454e4948444241'#递归函数中需要异或的数
key4=[int(a,16) for a in [key3[i:i+2] for i in range(0,len(key3),2)]]

#三个函数
def sub(a1,a2):
    key1[a1] -= a2
def abs1(a1,a2):
    temp2 = key1[a1] + key1[a2] - 0xff - 1 #key1[a2]大
    key1[a1] = temp2
def abs2(a1,a2):
    temp1 = key1[a2] - key1[a1] + 0xff + 1  # key1[a2]小
    key1[a1] = temp1
def xor(a1,a2):
    key1[a1] ^= key1[a2]

#逆着来,先异或
for v4 in range(0, 15):
    key1[v4] ^= key4[v4]

#调用七次函数,逆着来
d=[6, 5, 4, 3, 2, 1, 0]
for i in d :
    if i==0 or i==5 or i==6:
        sub(i,i+1)
    if i==1 or i==3:
        xor(i,i+1)
    if i==4:
        abs1(i,i+1)
    if i==2:
        abs2(i,i+1)
        
#将10进制变为16进制
for x in range(16):
    key1[x]=hex(key1[x])
print(key1)

key1=[0x27,0x62,0x49,0x27,0x45,0x49,0x74,0x25,0x77,0x63,0x62,0x7f,0x70,0x63,0x27,0x37] #将数字颠倒

for x in range(0,16):
    key1[x] ^= 0x16
    key1[x] = (chr(key1[x]))
print(''.join(key1)) # 得到flag moectf1t_1S_b3autifu1!

以上是关于[MoeCTF 2021]地狱通讯的主要内容,如果未能解决你的问题,请参考以下文章

2020moectf—flower

2020moectf—flower

在 SQL 查询之外导出值(回调地狱)[重复]

什么是地狱回调?解决回调地狱的两种方法

回调地狱以及用promise怎么解决回调地狱

CTF实战(隐写术):欢迎来到地狱