RE WP October 28, 2019

buuctf re wp

Words count 12k Reading time 11 mins. Read count 1000000

youngter-drive

https://hx1997.github.io/2018/07/22/anheng-july-re-youngter-drive/

crackRTF

https://www.52pojie.cn/thread-994588-1-1.html
补充一些知识点:
有个PDB文件的类型

PDB(Program Database File,程序数据库文件)文件物理结构在我们目前使用的掌上电脑中,Palm操作系统由于其功能强大、应用软件多等特点,占有很大的比例。PDB文件是Palm OS操作系统上数据文件类型。一般我们在使用Palm系统的电子书时都会遇到这种文件,一般用于电子书或手机电子书 pdb是Palm DataBase的缩写,Palm OS所用文件的扩展名为“.pdb”。还表示碳氧同位素标准样品以及可编程延迟模块,是DSP中的一种模块,可以用来计数和延时。
可以使用PalmReader打开。如果想把PDB文件转换成TXT文件查看,可以使用WavePDB转。
https://baike.baidu.com/item/pdb/5357352

[GXYCTF2019]simple CPP

先查看文件类型

用PEid看看是否有什么加密算法

看来是没有

直接拖进ida64查看内容吧

有很多的函数,并且没有看到main函数,那就只能从字符串找找有什么突破口

看到congratulations了,看来这部分可能与flag有关系了,进去看看。

看到这个函数后,光读后面的部分就可以知道判断条件是什么,如下

// v20 = 1176889593874
// v20 = v15[2]&~v15[0]
// v24 = 4483974544037412639
// v24=(v15[2]&~v15[0])|(v15[1]&v15[0])|(v15[2]&~v15[1])|(v15[0]&~v15[1])
// v27=577031497978884115
// v27=((v15[2]&~v15[1])&v15[0])|(v15[2]&((v15[0]&v15[1])|(v15[1]&~v15[0])|~(v15[1]|v15[0])))
// (v24 ^ v15[3]) == 4483974543195470111
// v15[2]&~v15[0]|v15[0]&v15[1]|v15[1]&v15[2] = ~v15[0]&v15[2]|864693332579200012

自己算的话不太可能,这时候可以借助z3求解器来解决计算问题代码如下:

from z3 import *
a,b,c,d=BitVecs('a b c d',64)
s=Solver()
s.add(~a&c==1176889593874)
s.add((c&~a)|(b&a)|(c&~b)|(a&~b)==4483974544037412639)
s.add(((c&~b)&a)|(c&((a&b)|(b&~a)|~(b|a)))==577031497978884115)
s.add(((c&~a)|(b&a)|(c&~b)|(a&~b))^d==4483974543195470111)
#print s.model()
print s.check()
print s.model()

算出来的答案如下:

sat
[w = 842073600,
 y = 4483973367147818765,
 x = 4483973367147818765,
 z = 577031497978884115]

感觉Y有点问题,不过先不管了。

把这几个数字转成十六进制再拼起来,后面会用到。

Y的部分直接都改成0x0

上图的最下面的循环是很重要的一部分,是判断用来你输入是否是答案,这个v3就是刚才的v15,v7是上面的Dst,但是你没办法判断Dst的值,这时候看交叉引用来判断是哪个函数为它赋值的。如下图:

进去查看该函数

读几个关键部分其实就能够知道Dst被赋值为”i_will_check_is_debug_or_not”

知道这些就够了,把我之前说的那个循环写个脚本就可以跑出来了。

脚本如下:

a="i_will_check_is_debug_or_not"
b = [0x3e,0x3a,0x46,0x05,0x33,0x28,0x6f,0x0d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x08,0x2,0x07,0x17,0x15,0x3e,0x30,0x13,0x32,0x31,0x06,0x00,0x00]
c=''
for i in range(0,27):
        c += chr(ord(a[i%27])^b[i])

print c

y刚才说有问题,后来看官方wp应该是给hint补充了,这样子flag就出来了

flag{We1l_D0ne!P0or_algebra_am_i}

findkey

放入detect it 检查发现是32位程序,而且是个PDB文件。

PDB(Program Database File,程序数据库文件)文件物理结构在我们目前使用的掌上电脑中,Palm操作系统由于其功能强大、应用软件多等特点,占有很大的比例。PDB文件是Palm OS操作系统上数据文件类型。一般我们在使用Palm系统的电子书时都会遇到这种文件,一般用于电子书或手机电子书 pdb是Palm DataBase的缩写,Palm OS所用文件的扩展名为“.pdb”。

但这里并不是重点。

再把它放到PEid中看一下有没有什么加密函数,

点开细看可以看到是md5加密,md5的题目有需要爆破的可能性,再放到ida里看。

进入ida可以看到函数窗口里有winmain,进入看函数伪代码,应该是程序主界面的参数调整等,这部分不是很重要,接着往下看,看完所有函数的伪代码,只发现有一部分像加密的部分,如下图:

尝试跳转外部引用发现会跳转到一块汇编语言,左边是红色的部分可以猜测可能是花指令扰乱了正常汇编,先把左边的红色部分的地址用P键创建函数,然后发现有三个地方无法生成伪代码,先不管那些那些部分,先把生成的正常的部分看一下,有没有重要的部分。在寻找的过程中找到这个函数,

v14和v18是重要的变量,进入sub_401005这个函数,

函数的算法加密过程并不难理解,两个参数都是已知的,就是v14和v18,可以写出脚本看一下,

key1=[]
key=''
key2='0kk`d1a`55k222k2a776jbfgd`06cjjb'
for i in range(len(key2)):
    key1.append(chr(ord(key2[i])^83))
    key+=chr(ord(key2[i])^83)
print(key)

结果是 c8837b23ff8aaa8a2dde915473ce0991(也就是v18)

之后会经过一个strcmpi的函数进行比较

相等的话说明string1也是这个值,string1经过了一次md5的加密,这时候打开百度,查找md5解密可以破解出来string1的值应该为‘123321’

然后后面还有一个sub_401005,这次重点是v22和v13,v22是刚开始的string1也就是’123321’,v13就是那个byte_423030,然后根据这些可以写出脚本。

key1='123321'
key2=[87,94,82,84,73,95,1,109,105,70,2,110,95,2,108,87,91,84,76]
key=''
for i in range(len(key2)):
    key += chr(key2[i]^ord(key1[i%len(key1)]))
print(key)

结果是flag{n0_Zu0_n0_die}

这就是本次的答案

[SUCTF2019]SignIn

本道题是一道RSA的题目有关RSA的算法可以上网查阅。

放到detectit查看是64位linux的文件,放到peid中查看是否有算法,看到有大数后可以猜测是RSA的算法。

进入ida查看程序

那个sub_96A不是重要的步骤,很容易懂,所以就不做分析了。

重要的是gmpz_init_set_str和gmpz_pown这两个函数,前者是用来初始化变量,后一个是将M的E次方模N放入M中。这两个函数是开源的数据库中的函数

GMP,是GNU MP Bignum库的缩写,意思是开源数学运算库。GMP是GNU MP Bignum库,是一个开源的数学运算库,它可以用于任意精度的数学运算,包括有符号整数,有理数和浮点数。

看来可以用来算大数运算。

前面分析了两个重要的函数的作用,再加上65537这些数字就已经可以确定是RSA了,直接按照破解rsa的流程就可以了。

首先要把大数N分解了,用yafu就可以了如下图:

这样P和Q就知道了,还需要求欧拉函数,私钥,其实已经显而易见了,写个脚本就能出来了。

import gmpy2

p = 366669102002966856876605669837014229419
q = 282164587459512124844245113950593348271
N = 103461035900816914121390101299049044413950405173712170434161686539878160984549
c = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
e = 65537

d = gmpy2.invert(e,(p-1)*(q-1))
m = gmpy2.powmod(c,d,p*q)

print hex(m)[2:].decode('hex')

(说一下gmpy2的安装好麻烦233333~。)

[2019红帽杯]xx

这题目花了我好长时间复现(因为真的是做不出来),不愧是最菜选手(哭)

放到detectit查看是64位PE文件,去peid中查看算法,发现是这么描述的

A single DWORD, used in multiple crypto algorithms (TEA/N, RC 5/6, SERPENT, ISAAC, etc).

看来有可能是tea类的或是RC类的算法加密等等。

进入ida细看一下吧

发现又是一堆函数,这时候只能查看字符串了,发现you win这个地方有可能和flag有关系,进入查看伪代码。

很长。。。。。。。

一部分一部分看吧

第一部分

这一部分是用来取出输入的flag的前四个字母,这个应该是众所周知的‘flag’的这四个字母,然后与code这个变量进行比较,是否是这个变量中的字母或数字。

第二部分:

这一部分是进行xxtea的加密,其中sub_140001ab0就是加密的过程,这里就不放出来了,里面写的很复杂,不是很容易懂,这里放一个链接,大概了解一下xxtea原理

https://odoiys.github.io/2020/01/29/xxtea%E5%AD%A6%E4%B9%A0/

继续往下看第三部分:

主要进行了将xxtea加密后的数组进行打乱,然后进行异或操作,最后进行和给出的&v31,&v31+1,&v32,v33进行比较,这里是小端序,所以需要把它倒过拼接起来,拼接后的结果为:

CEBC406B7C3A95C0EF9B202091F70235231802C8E75656FA

过程清楚后写脚本来得到flag吧

import xxtea
data0 = "CEBC406B7C3A95C0EF9B202091F70235231802C8E75656FA"#为提取出来的v29,v29+1,v30,v31
data = []
for i in range(0,len(data0),2):
    data.append(int(data0[i]+data0[i+1],16))#每两位为整体,将16进制转换为10进制
print(data)
for i in range(len(data)-1,-1,-1):
    for j in range(i//3):
        data[i] ^= data[j]
        #进行的异或操作
print(data)
change=[2,0,3,1,6,4,7,5,10,8,11,9,14,12,15,13,18,16,19,17,22,20,23,21]
data1=[0 for i in range(24)]
#print(data1)
for i in range(24):
    data1[change[i]]=data[i]
print(data1)
#encrypt_data='bca5ce40f4b2b2e7a9129d12ae10c85b3dd7061ddc70f8dc'.decode('hex')
#print(encrypt_data)
key = "flag"
encrypt_data=''
for i in range(len(data1)):
    encrypt_data+=str(hex(data1[i]))
print(encrypt_data)
#bca5ce40f4b2b2e7a9129d12ae10c85b3dd761ddc70f8dc
encrypt_data='bca5ce40f4b2b2e7a9129d12ae10c85b3dd7061ddc70f8dc'.decode('hex')
print(encrypt_data)
key='flag\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
decrypt_data = xxtea.decrypt(encrypt_data,key,padding=False)
#decrypt_data = xxtea.decrypt(encrypt_data,key)
print decrypt_data

这样就可以得到flag了

那阵还看到脚本更强的,还有把xxtea直接写出来,还有动态调试读流程的,简直无敌。

flag{CXX_and_++tea}

[GWCTF 2019]re3

放入detectit中可以看到是elf64,再放到peid中查看有哪些加密,md5,aes,base64,感觉很复杂的样子,进入ida64里看一下。

直接进入main函数,看到一个异或操作,这个操作是用来把函数内容变换,这样子就没办法静态直接看到,可以选择用ida远程调试linux来动态查看sub_402219的真正面貌,之前还有个sub_40207b那个函数并没有对输入进行改变暂时不用看。sub_402219如下:

v4就是aes的key,byte_6030a0就是aes的加密结果,然后可以写脚本来解密:

from Crypto.Cipher import AES
cipher1 = [0xBC, 0x0A, 0xAD, 0xC0, 0x14, 0x7C, 0x5E, 0xCC, 0xE0, 0xB1, 0x40, 0xBC, 0x9C, 0x51, 0xD5, 0x2B, 0x46, 0xB2, 0xB9, 0x43, 0x4D, 0xE5, 0x32, 0x4B, 0xAD, 0x7F, 0xB4, 0xB3, 0x9C, 0xDB, 0x4B, 0x5B]
key1 = [0xcb, 0x8d, 0x49, 0x35, 0x21, 0xb4, 0x7a, 0x4c, 0xc1, 0xae, 0x7e, 0x62, 0x22, 0x92, 0x66, 0xce]
#cipher = bytes(cipher1)
cipher='\xBC\x0A\xAD\xC0\x14\x7C\x5E\xCC\xE0\xB1\x40\xBC\x9C\x51\xD5\x2B\x46\xB2\xB9\x43\x4D\xE5\x32\x4B\xAD\x7F\xB4\xB3\x9C\xDB\x4B\x5B'
#key = bytes(key1)
key='\xcb\x8d\x49\x35\x21\xb4\x7a\x4c\xc1\xae\x7e\x62\x22\x92\x66\xce'
print(key)
aes = AES.new(key, mode=AES.MODE_ECB)
flag = aes.decrypt(cipher)
print(flag)

flag{924a9ab2163d390410d0a1f670}

下次一定更一下aes的原理,以上只是简单写一下wp的流程。下次一定下次一定。

emm,下面是AES的介绍,可以大概学习一下

https://odoiys.github.io/2020/02/01/AES%E5%8A%A0%E5%AF%86%E5%AD%A6%E4%B9%A0/

[GUET-CTF2019]re

用detectit查看是个elf64并且有UPX壳,用UPX工具自动脱壳,用PEID查看没有加密算法。进入ida查看代码。

并没有发现main函数,只能查找字符串来寻找信息。发现input your flag,correct等,就进到这里查看伪代码。

查看if判断的那个函数,参数是&v1

直接写脚本就可以求得

a=[0 for i in range(31)]
a[0] = 166163712//1629056
a[1] = 731332800//6771600
a[2] = 357245568//3682944
a[3] = 1074393000//10431000
a[4] = 489211344//3977328
a[5] = 518971936//5138336
a[6] = 406741500//7532250
a[7] = 294236496//5551632
a[8] = 177305856//3409728
a[9] = 650683500//13013670
a[10] = 298351053//6088797
a[11] = 386348487//7884663
a[12] = 438258597//8944053
a[13] = 249527520//5198490
a[14] = 445362764//4544518
a[15] = 981182160//10115280
a[16] = 174988800//3645600
a[17] = 493042704//9667504
a[18] = 257493600//5364450
a[19] = 767478780//13464540
a[20] = 312840624//5488432
a[21] = 1404511500//14479500
a[22] = 316139670//6451830
a[23] = 619005024//6252576
a[24] = 372641472//7763364
a[25] = 373693320//7327320
a[26] = 498266640//8741520
a[27] = 452465676//8871876
a[28] = 208422720//4086720
a[29] = 515592000//9374400
a[30] = 719890500//5759124
#a[31] = 357245568//3682944
flag=''
for i in range(len(a)):
    flag+=chr(a[i])
print(flag)

注意原函数中并没有a1[6],所以我选择一个一个试出来发现1是答案。

flag{e165421110ba03099a1c039337}

0%