hgame2020-week2-re

hgame week2

hgame ctf week2的逆向wp
题目链接:
链接: https://pan.baidu.com/s/1mmUxYJ-bfh-hf2akSiMRCA
密码: um92

文章目录

  • hgame week2
  • unpack
  • crackme
  • baby py
  • baby pyc
    • python字节码
    • pythonu

unpack

这是一个elf脱壳的题目,我用的方法是先运行程序,然后使用gdb attach到程序,然后dump出来,

首先是先使程序运行起来,

然后查一下这个程序运行时该进程的pid, 使用ps和grep指令,

然后看一下这个进程空间,cat /proc/[pid]/maps
hgame2020-week2-re_第1张图片

然后使用gdb去:gdb attach [pid]

这里我是要使用root才可以attack成功,有点奇怪?

然后进入以后使用gdb的dump指令,

dump binary memory [path] start_addr end_addr
hgame2020-week2-re_第2张图片

这里整个dump下来,然后就可以得到这个文件,看到加密还是很简单:

hgame2020-week2-re_第3张图片

在ida可以看到地址,然后下断,继续运行程序,可以在得到内存中的值:

然后直接可以得到flag:

hgame2020-week2-re_第4张图片

crackme

首先查壳是一个.net文件,用dnSpy做的,打开可以直接诶看到源码,

private void button1_Click(object sender, EventArgs e)
{
	if (this.status == 1)
	{
		MessageBox.Show("你已经激活成功啦,快去提交flag吧~~~");
		return;
	}
	string text = this.textBox1.Text;
	if (text.Length != 46 || text.IndexOf("hgame{") != 0 || text.IndexOf("}") != 45)
	{
		MessageBox.Show("Illegal format");
		return;
	}
	string base64iv = text.Substring(6, 24);
	string str = text.Substring(30, 15);
	try
	{
		Aes aes = new Aes("SGc0bTNfMm8yMF9XZWVLMg==", base64iv);
		Aes aes2 = new Aes("SGc0bTNfMm8yMF9XZWVLMg==", "MFB1T2g5SWxYMDU0SWN0cw==");
		string text2 = aes.DecryptFromBase64String("mjdRqH4d1O8nbUYJk+wVu3AeE7ZtE9rtT/8BA8J897I=");
		if (text2.Equals("Same_ciphertext_"))
		{
			byte[] array = new byte[16];
			Array.Copy(aes2.EncryptToByte(text2 + str), 16, array, 0, 16);
			if (Convert.ToBase64String(array).Equals("dJntSWSPWbWocAq4yjBP5Q=="))
			{
				MessageBox.Show("注册成功!");
				this.Text = "已激活,欢迎使用!";
				this.status = 1;
			}
			else
			{
				MessageBox.Show("注册失败!\nhint: " + aes2.DecryptFromBase64String("mjdRqH4d1O8nbUYJk+wVu3AeE7ZtE9rtT/8BA8J897I="));
			}
		}
		else
		{
			MessageBox.Show("注册失败!\nhint: " + aes2.DecryptFromBase64String("mjdRqH4d1O8nbUYJk+wVu3AeE7ZtE9rtT/8BA8J897I="));
		}
	}
	catch
	{
		MessageBox.Show("注册失败!");
	}
}

中间是调用内部设置的一个aes的加密, 然后中间可以看到是一个CBC的方式,然后有两次判定,

首先第一次:比较text2, 这个位置前面是设置好了的一个keys和iv然后encode字符串解密出来,

注意了解CBC的加密方式,其解密的时候这个iv只有最后一次异或使用了一次,

我们看到输出提示的位置,用的是同样的keys和encode, 也就是说他的解密出来的字符str还未与iv疑惑之前是一致的,异或以后形成了不一样的decode1,2,也就是我们的iv1 = iv2 ^ decode1 ^ decode2:

import base64 

iv2 = str(base64.b64decode("MFB1T2g5SWxYMDU0SWN0cw=="), encoding = 'utf-8')
iv1 = ''
decode1 = "Same_ciphertext_"
decode2 = "Learn principles"

for i in range(16):
	iv1 += chr(ord(iv2[i]) ^ ord(decode1[i]) ^ ord(decode2[i]))
flag1 = str(base64.b64encode(bytes(iv1,encoding = 'utf-8')),encoding = 'utf-8')
print(flag1)

后面的一个就是加密,长度超出来了,然后就进行分组, 然后再加密,这里要注意,是进行了两次加密,最后加密的到的decode2是第二次加密的,
hgame2020-week2-re_第5张图片

我们要解决的是第二次加密的位置,分成两次,第一次iv, key,encode都知道,第二次,key和decode知道,我们需要解出来encode是啥,但是注意这个加密方式,我们前一次的密文作为下一次的iv, 所以第二次的iv应该是第一次的decode。

key = str(base64.b64decode("SGc0bTNfMm8yMF9XZWVLMg=="), encoding = 'utf-8')
iv_1 = str(base64.b64decode("MFB1T2g5SWxYMDU0SWN0cw=="), encoding = 'utf-8')
encode_1 = "Same_ciphertext_"
decode_2 = base64.b64decode("dJntSWSPWbWocAq4yjBP5Q==")

encode2 = ''

aes = AES.new(key, AES.MODE_CBC, iv_1)
decode_1 = aes.encrypt(encode_1)
iv_2 = decode_1
aes_2 = AES.new(key, AES.MODE_CBC, iv_2)
encode_2 = aes_2.decrypt(decode_2)
print(encode_2)
flag2 = str(encode_2, encoding = 'utf-8')
print(flag1 + flag2)

最后得到flag, hgame{L1R5WFl6UG5ZOyQpXHdlXw==DiFfer3Nt_w0r1d}

baby py

​ 得到一个dis出来的python字节码。然后对着一个官方文档看着,然后自己用ipython写,然后dis出来对照着搞出来的,

大致的算法如下:

def encrypt(flag):
    data1 = flag[::-1]
    data2 = list(data1)
    for i in range(1, len(data2)):
        a = data2[i-1] ^ data2[i]
        data2[i] = a
    b = bytes(data2)
    return hex(b)

解密脚本:

def decode():
    s = '7d037d045717722d62114e6a5b044f2c184c3f44214c2d4a22'
    arr = []
    ss = '}'
    for i in range(0,50,2):
        arr.append(int(s[i:i+2],16))
    for i in range(1,25):
        ss += chr(arr[i] ^ arr[i-1])
    print(ss[::-1])

得到flag:
hgame2020-week2-re_第6张图片

baby pyc

首先是使用uncompyle6去反pyc文件会产生一个报错,回显出来的是一大片的main函数的python字节码:

和baby py一样对着文档和自己一点点用dis搞:

python字节码

   3         0  JUMP_ABSOLUTE         2  'to 2'

             2  LOAD_CONST               0
             4  LOAD_CONST               None
             6  IMPORT_NAME              os
             8  STORE_NAME               os                    import os as os 

            10  LOAD_CONST               0
            12  LOAD_CONST               None
            14  IMPORT_NAME              sys
   4        16  STORE_NAME               sys                   import sys as sys

            18  LOAD_CONST               0
            20  LOAD_CONST               ('b64encode',)
            22  IMPORT_NAME              base64
            24  IMPORT_FROM              b64encode
            26  STORE_NAME               b64encode
   6        28  POP_TOP                                        from base64 import b64encode as b64encode 



            30  LOAD_STR                 '/KDq6pvN/LLq6tzM/KXq59Oh/MTqxtOTxdrqs8OoR3V1X09J'
   8        32  STORE_GLOBAL             O0o                  O0o = '/KDq6pvN/LLq6tzM/KXq59Oh/MTqxtOTxdrqs8OoR3V1X09J'


            34  LOAD_CODE                
            36  LOAD_STR                 'getFlag'
            38  MAKE_FUNCTION_0          ''
  16        40  STORE_NAME               getFlag
            42  LOAD_NAME                getFlag
            44  CALL_FUNCTION_0       0  ''
  18        46  STORE_NAME               flag

            48  LOAD_NAME                flag
            50  LOAD_CONST               None
            52  LOAD_CONST               6
            54  BUILD_SLICE_2         2 
            56  BINARY_SUBSCR    
            58  LOAD_STR                 'hgame{'             flag format:  hgame{   }
            60  COMPARE_OP               !=
            62  POP_JUMP_IF_TRUE     76  'to 76'              
            64  LOAD_NAME                flag
            66  LOAD_CONST               -1
            68  BINARY_SUBSCR    
            70  LOAD_CONST               125
            72  COMPARE_OP               !=


  19        74  POP_JUMP_IF_FALSE    94  'to 94'
          76_0  COME_FROM            62  '62'
            76  LOAD_NAME                print                   print('Incorrect format!')
            78  LOAD_STR                 'Incorrect format!'
            80  CALL_FUNCTION_1       1  ''
  20        82  POP_TOP          
            84  LOAD_NAME                sys                     sys.exit()
            86  LOAD_METHOD              exit
            88  LOAD_CONST               1
            90  CALL_METHOD_1         1  ''



  22        92  POP_TOP          
          94_0  COME_FROM            74  '74'
            94  LOAD_NAME                flag                   raw_flag = flag[6:-1]
            96  LOAD_CONST               6
            98  LOAD_CONST               -1
           100  BUILD_SLICE_2         2 
           102  BINARY_SUBSCR    
  23       104  STORE_NAME               raw_flag



           106  LOAD_NAME                len
           108  LOAD_NAME                flag
           110  CALL_FUNCTION_1       1  ''                       len(flag) - 7 != 36 
           112  LOAD_CONST               7
           114  BINARY_SUBTRACT  
           116  LOAD_CONST               36
           118  COMPARE_OP               !=



  24       120  POP_JUMP_IF_FALSE   140  'to 140'                  
           122  LOAD_NAME                print                    print('Worng length!')
           124  LOAD_STR                 'Wrong length!'
           126  CALL_FUNCTION_1       1  ''
  25       128  POP_TOP          
           130  LOAD_NAME                sys                      sys.exit()
           132  LOAD_METHOD              exit
           134  LOAD_CONST               2Python的字节码混淆
           136  CALL_METHOD_1         1  ''



  27       138  POP_TOP          
         140_0  COME_FROM           120  '120'
           140  LOAD_NAME                raw_flag                 raw_flag = raw_flag[::-1]
           142  LOAD_CONST               None
           144  LOAD_CONST               None
           146  LOAD_CONST               -1
           148  BUILD_SLICE_3         3 
           150  BINARY_SUBSCR    


  28       152  STORE_NAME               raw_flag
           154  LOAD_LISTCOMP            '>'
           156  LOAD_STR                 ''
           158  MAKE_FUNCTION_0          ''
           160  LOAD_NAME                range结束
           162  LOAD_CONST               6
           164  CALL_FUNCTION_1       1  ''
           166  GET_ITER         
           168  CALL_FUNCTION_1       1  ''
  30       170  STORE_NAME               ciphers                   ciphers <===  raw_flag



           172  SETUP_LOOP          260  'to 260'
           174  LOAD_NAME                range
           176  LOAD_CONST               5       
           178  CALL_FUNCTION_1       1  ''
           180  GET_ITER         
           182  FOR_ITER            258  'to 258'      for  row in range(5)
  31       184  STORE_NAME               row
           186  SETUP_LOOP          256  'to 256'
           188  LOAD_NAME                range
           190  LOAD_CONST               6
           192  CALL_FUNCTION_1       1  ''
           194  GET_ITER         
           196  FOR_ITER            254  'to 254'       for  col in range(6)
  32       198  STORE_NAME               col


           200  LOAD_NAME                ciphers
           202  LOAD_NAME                row
           204  BINARY_SUBSCR                         
           206  LOAD_NAME                col
           208  DUP_TOP_TWO                           
           210  BINARY_SUBSCR                          cipher[col + row]                            
           212  LOAD_NAME                ciphers
           214  LOAD_NAME                row
           216  LOAD_CONST               1
           218  BINARY_ADD       
           220  BINARY_SUBSCR            
           222  LOAD_NAME                col
           224  BINARY_SUBSCR                          cipher[col + row + 1]

           226  INPLACE_ADD                      
           228  ROT_THREE        
  33       230  STORE_SUBSCR                           cipher[col + row] += cipher[col + row + 1]

           232  LOAD_NAME                ciphers
           234  LOAD_NAME                row
           236  BINARY_SUBSCR    
           238  LOAD_NAME                col
           240  DUP_TOP_TWO      
           242  BINARY_SUBSCR    

           244  LOAD_CONST               256  

           246  INPLACE_MODULO                         
           248  ROT_THREE        
           250  STORE_SUBSCR                           cipher[row + col] %= 256


           252  JUMP_BACK           196  'to 196'
           254  POP_BLOCK                                  for col in range结束  
         256_0  COME_FROM_LOOP      186  '186'
           256  JUMP_BACK           182  'to 182'
  35       258  POP_BLOCK                                  for  row in range结束  
         260_0  COME_FROM_LOOP      172  '172'




           260  LOAD_STR                 ''                 
  36       262  STORE_NAME               cipher            cipher = ''



           264  SETUP_LOOP          336  'to 336'
           266  LOAD_NAME                range
           268  LOAD_CONST               6
           270  CALL_FUNCTION_1       1  ''
           272  GET_ITER         
           274  FOR_ITER            334  'to 334'           for  row  in range(6) 
  37       276  STORE_NAME               row


           278  LOAD_CONST               0
  38       280  STORE_NAME               col               col = 0 

           282  SETUP_LOOP          330  'to 330'
           284  LOAD_NAME                col               while  col < 6:
           286  LOAD_CONST               6
           288  COMPARE_OP               <
       290_292  POP_JUMP_IF_FALSE   328  'to 328'
           294  LOAD_NAME                cipher             
           296  LOAD_NAME                bytes
           298  LOAD_NAME                ciphers
           300  LOAD_NAME                row
           302  BINARY_SUBSCR    
           304  LOAD_NAME                col
           306  BINARY_SUBSCR    
           308  BUILD_LIST_1          1 
           310  CALL_FUNCTION_1       1  ''               
           312  INPLACE_ADD      
  40       314  STORE_NAME               cipher           cipher += bytes(ciphers[row + col])
           316  LOAD_NAME                col
           318  LOAD_CONST               1
           320  INPLACE_ADD      Python的字节码混淆
           322  STORE_NAME               col              col += 1
       324_326  JUMP_BACK           284  'to 284'         while循环结束
         328_0  COME_FROM           290  '290'

           328  POP_BLOCK        
         330_0  COME_FROM_LOOP      282  '282'
       330_332  JUMP_BACK           274  'to 274'        
  42       334  POP_BLOCK
         336_0  COME_FROM_LOOP      264  '264'            for row in range(6) 结束


           336  LOAD_NAME                b64encode
           338  LOAD_NAME                cipher
           340  CALL_FUNCTION_1       1  ''
  44       342  STORE_NAME               cipher           cipher = b64encode(cipher)



           344  LOAD_NAME                cipher 
           346  LOAD_GLOBAL              O0o 
           348  COMPARE_OP               ==                        if cipher == O0o:
       350 352  POP_JUMP_IF_FALSE   364  'to 364'
           354  LOAD_NAME                print                     print('Great')
           356  LOAD_STR                 'Great, this is my flag.'
           358  CALL_FUNCTION_1       1  ''
           360  POP_TOP          
  47       362  JUMP_FORWARD        372  'to 372'                  else:
         364_0  COME_FROM           350  '350'
           364  LOAD_NAME                print                      print('Wrong')
           366  LOAD_STR                 'Wrong flag.'
           368  CALL_FUNCTION_1       1  ''
           370  POP_TOP          
           372  COME_FROM           362  '362'

pythonu

大致源码做出来是这样:

def encode ():
	import os as os 
	import sys as sys
	from base64 import b64encode as b64encode 
	O0o = '/KDq6pvN/LLq6tzM/KXq59Oh/MTqxtOTxdrqs8OoR3V1X09J'
	getflag = getflag
	flag = getflag()
	if flag[:6] != 'hgame{' and flag[-1] != '}':
		print('format!')
		sys.exit()
	raw_flag = flag[6:-1]
	if len(flag) - 7 != 36 :
		print('len!')
		sys.exit()
	raw_flag = raw_flag[::-1]

	#ciphers <<==  raw_flag   ###
	cipher = [[flag[6*i+j]for i in range(6)] for j in range(6)]
	for row in range(5):
		for col in range(6):
			ciphers[row][col] += ciphers[row+1][col]
			ciphers[row][col] %= 256
	cipher = ''
	for row in range(6):
		col = 0 
		while col < 6:
			cipher += bytes(ciphers[row][col])
			col += 1
	cipher = b64encode(cipher)
	if cipher == O0o :
		print('Great!')
	else:
		print('Wong!')

主要的是一个base64解出来以后是一个后项加钱项然后又对0xff取余,这里我们直接后项减去前项,然后和0xff按位与可以还原,

但是注意这个加密时先通过一个二位数组,把顺序变换了,我们在解的时候要注意,

def decode():
	s = ''
	dd1 = '\xfc\xa0\xea\xea\x9b\xcd\xfc\xb2\xea\xea\xdc\xcc\xfc\xa5\xea\xe7\xd3\xa1\xfc\xc4\xea\xc6\xd3\x93\xc5\xda\xea\xb3\xc3\xa8Guu_OI'
	dd = 'B\x97\xb9\xb1\x94\x9eZ\xbd\xc2\xd1\x93xq\xe7\xea\xef\xd3\xbc\x9f\xb8\xfa\xda\xdf\xcd\xce\xb7\xae\xa3\xcd\xa9gr0E^P'
	b = [[ord(dd[6 * i:6*(i+1)][j]) for j in range(6)] for i in range(6)]
	#print(b)
	for i in range(4,-1,-1):
		for j in range(5,-1,-1):
			b[i][j] = b[i][j] - b[i+1][j]
	for i in range(6):
		for j in range(6):
			s += (chr(b[j][i]&0xff))
		#print('\n')
	print(s[::-1])

这是解密脚本,其中,dd1是我们在字节码中看到的,靠dd1解出来的flag是这样的:

然后提交不对,这个真的是个假flag,然后想起来这个字符串在字节码中显示是一个:STORE_GLOBAL, 说明我们的调用函数的时候某个函数改变了这个值, 但是我们只看到main函数所以不知,

直接在010中看一下, 找到了另一个长度一致的字符串, 就是我们的dd, 然后修改过来,,就是我们的flag,

你可能感兴趣的:(题目的整理,逆向)