RE WP February 07, 2020

2020hgame-re-wp

Words count 5.7k Reading time 5 mins. Read count 1000000

本来出于个人原因是不想做hgame的,但是做了发现出题很有水品,害,真香。

WEEK2:

unpack:

这道题有两种思路都要学会,官方给的那种方法(第一种方法)更好一些,直接给这两个链接。

第一种方法:

https://www.52pojie.cn/thread-1048649-1-1.html

第二种方法:

https://blog.csdn.net/Palmer9/article/details/104119621

flag脚本在第二种方法里有给

Classic_CrackMe:

放入detectit中查看,这是一道C#的逆向题目。可以用dnspy来反编译看源码。

进入Form1中看到加密部分,可以看出来是一道AES的加密。

代码写的很巧妙(太烧脑了不得不说)。

大概说一下加密的流程,然后可以根据这个流程逆向出来。(他们都问我为什么哭着做题,幼稚园真的太强了)

你所输入的答案两边会被加上hgame{和},然后变成新的一个字符串。这个字符串被分成了两部分

第一部分从第6个字符到第29个字符,第二个部分从第29个字符到第44个字符。

第一部分被当做aes的iv,第二部分被用作aes2的加密的后半部分。

text2是”mjdRqH4d1O8nbUYJk+wVu3AeE7ZtE9rtT/8BA8J897I=”用aes解密前的明文,text2又是”Same_ciphertext_”

array是text2+str用aes2加密后的密文的后16个字符也就是后半部分,array同时也是”dJntSWSPWbWocAq4yjBP5Q==”

下面是官方wp:

输⼊的flflag除去两头之后分成两部分。第⼀部分是⽬标iv,已知密⽂、⽬标明⽂和key,如果直接算会⽐较复杂,但题⽬还有⼀个条件:已知的密⽂是原明⽂⽤原iv加密之后得到的。理解cbc原理之后,我们能得到这个式⼦

中间值的第⼀组 ^ 原iv = 原明⽂的第⼀组

中间值的第⼀组 ^ ⽬标iv = ⽬标明⽂的第⼀组

⽬标iv = 原iv ^ 原明⽂的第⼀组 ^ ⽬标明⽂的第⼀组

那这个iv就很好求了

接下来,⽬标明⽂和flflag的第⼆段合并之后⽤原iv加密,对密⽂的后半段进⾏⽐较。结合cbc原理,可以看到第⼆组会与第⼀组密⽂异或,所以只要将第⼀组密⽂作为新的iv,对第⼆组密⽂(后半段密⽂)解密即可 当然第⼀组的密⽂和第⼆组的密⽂拼接在⼀起,然后⽤原iv解密,也是可以的。不过要注意的是,第⼀组明⽂是16字节的,所以单独对它加密时会另padding 16个字节的0x10,因此单独加密时得到的密⽂要切掉后半部分才能和第⼆组密⽂拼接

import hashlib
from Crypto.Cipher import AES
import base64
class AesCrypter(object):
 def __init__(self, key, iv):
  self.key = key
  self.iv = iv
 def encrypt(self, data):
  data = self.pkcs7padding(data)
  cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
  encrypted = cipher.encrypt(data)
  return encrypted
 def decrypt(self, data):
  data = base64.b64decode(data)
  cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
  decrypted = cipher.decrypt(data)
  decrypted = self.pkcs7unpadding(decrypted)
  return decrypted
 def pkcs7padding(self, data):
  bs = AES.block_size
  padding = bs - len(data) % bs
  padding_text = chr(padding) * padding
  return data + padding_text
 def pkcs7unpadding(self, data):
  lengt = len(data)
  unpadding = ord(data[lengt - 1])
  return data[0:lengt-unpadding]
if __name__ == '__main__':
 key = base64.b64decode('SGc0bTNfMm8yMF9XZWVLMg==')
 OriginalIV = base64.b64decode('MFB1T2g5SWxYMDU0SWN0cw==')
 Part1Plaintext = 'Same_ciphertext_'
 OriginalAes = AesCrypter(key,OriginalIV)
 OriginalPlain=OriginalAes.decrypt('mjdRqH4d1O8nbUYJk+wVu3AeE7ZtE9rtT/8BA8J897I=')
 NewIV = ''
 for i in range(16):
  NewIV +=chr(ord(OriginalPlain[i])^ord(OriginalIV[i])^ord(Part1Plaintext[i]))
 print 'part1: ' + NewIV
 HalfPart2Ciphertext = OriginalAes.encrypt(Part1Plaintext)[0:16]
 Part2Cipher = HalfPart2Ciphertext +base64.b64decode('dJntSWSPWbWocAq4yjBP5Q==')
 Part2Plaintext = OriginalAes.decrypt(base64.b64encode(Part2Cipher))
 print Part2Plaintext
 print 'part2: ' + Part2Plaintext[16:]
 flag = 'hgame{' + base64.b64encode(NewIV) + Part2Plaintext[16:] + '}'
 print flag

这次真的哭了。

babypy

这个题目是阅读python的字节码,然后写出python源码,再解密。

可以看着官方文档来阅读:

https://docs.python.org/3/library/dis.html#python-bytecode-instructions

源码如下:

def encrypt(OOo):
 O0O = OOo[::-1]
 O0o = list(O0O)
 for O0 in range(1, len(O0o)):
  Oo = O0o[O0-1] ^ O0o[O0]
  O0o[O0] = Oo
 O = bytes(O0o)
 return O.hex()

解密脚本如下:

a="\x7d\x03\x7d\x04\x57\x17\x72\x2d\x62\x11\x4e\x6a\x5b\x04\x4f\x2c\x18\x4c\x3f\x44\x21\x4c\x2d\x4a\x22"
#print(len(a))
b=a[::-1]
print(len(b))
d=[0 for i in range(0,len(b))]
for i in range(0,len(b)-1):
    c=ord(b[i])^ord(b[i+1])
    d[i]=c
print(d)
flag=''
for i in range(0,len(b)):
    flag+=chr(d[i])
print(flag)

week3:

oooollvm:

一道很简单的ollvm题目,根本没进行什么过多的题目,所以整个题目难度很低。

直接放到ida中,首先先下断点,如图,忽略掉所有的分发器,只要断点下面的有效代码就可以了,这是简单ollvm题目的通用方法:

然后就是动态调试的方法,直到碰到加密的地方为止,函数开始就要求输入34个字符串,然后一直单步到这个位置:

直接写脚本跑出来就好了

table1=[0x22,0xcb,0x7d,0xaf,0x11,0x6f,0x22,0xa9,0xd,0x8e,0x42,0x38,0x1e,0x95,0x40,0x97,0xb4,0xb6,0x31,0xa4,0x4b,0x5,0x62,0x98,0x81,0x9b,0xa9,0x1f,0x63,0x34,0x47,0x80,0x3e,0xb9]
table2=[0x4a,0xab,0x1e,0xdf,0x70,0xf,0x47,0xfc,0x79,0xc1,0x1,0x1c,0x43,0xd1,0x63,0xe5,0xf4,0xaa,0x33,0xdb,0x3a,0x62,0x6,0xed,0xec,0xc0,0x9d,0x49,0x5e,0x1c,0x15,0xf3,0x3b,0xa7]
s=[]
for i in range(34):
    for x in range(0,255):
        if table2[i]==(x & 0x32AF3201 | ~x & 0xCD50CDFE)^((i+table1[i])&0x32AF3201|~(i+table1[i])&0xCD50CDFE):
            s.append(x)
print(s)
flag=''
for i in range(34):
    flag+=chr(s[i])
print(flag)

因为比较简单,本题也就大概说说ollvm的解题原理,以后专门更一个ollvm的解题方法。

0%