ctf

unctf的writeup

unctf的writeup

Posted by gxkyrftx on October 26, 2019

CRYPTO

1.一句话加密

1.1 题目内容

一张图片e.png如下 e

一个脚本内容如下


c = pow(int(m.encode('hex'), 16),e,n)

c1:62501276588435548378091741866858001847904773180843384150570636252430662080263

c2:72510845991687063707663748783701000040760576923237697638580153046559809128516

1.2 分析

根据脚本,先猜是rsa

n不知道,从图片入手,试了很多方法,最后用winhex打开图片,在尾部发现了

1572506021984

提取出来这个数

>>> 0xc2636ae5c3d8e43ffb97ab09028f1aac6c0bf6cd3d70ebca281bffe97fbe30dd
87924348264132406875276140514499937145050893665602592992418171647042491658461L
>>>

然后尝试分解,可以分解,得到

275127860351348928173285174381581152299<39> · 319576316814478949870590164193048041239<39>

应该就是p,q了

c1,c2应该就是两次加密的结果

然后尝试rsa,发现e不知道,穷举了很多之后,发现应该不是rsa,而是另外的一个基于大整数分解问题的体系,rabin加密。

1.3 脚本

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import gmpy2
import libnum
#c = 62501276588435548378091741866858001847904773180843384150570636252430662080263
c=72510845991687063707663748783701000040760576923237697638580153046559809128516
p = 275127860351348928173285174381581152299
q = 319576316814478949870590164193048041239
n = p*q
r = pow(c,int((p+1)/4),p)
s = pow(c,int((q+1)/4),q)
a = gmpy2.invert(p,q)
b = gmpy2.invert(q,p)
x =(a*p*s+b*q*r)%n
y =(a*p*s-b*q*r)%n

print libnum.n2s(x)
print libnum.n2s(n-x)
print libnum.n2s(y)
print libnum.n2s(n-y)
#unctf{412a1ed6d21e55191ee5131f266f5178}

REVERSE

1.checkhex

1.1 题目

一个win32的exe文件,打开之后的主函数内容如下

int __cdecl main(int argc, const char **argv, const char **envp)
{
  ...

  __main();
  puts("show me your flag:");
  scanf_s("%s", v4, 39);
  if ( v4[0] != 'f' || v4[1] != 'l' || v4[2] != 'a' || v5 != 'g' || v6 != '{' || v8 != '}' )// 确定了6个字符
  {
    puts("wrong flag!");
    system("pause");
    exit(0);
  }
  v12 = &v7;
  for ( i = 0; i <= 15; ++i )
  {
    v11 = char2hex(v12[i]);                     // 低字节字符转16进制
    v10 = char2hex(HIBYTE(v12[i]));             // 高字节字符转16进制
    if ( v11 == -1 || v10 == -1 )
    {
      puts("wrong flag!");
      system("pause");
      exit(0);
    }
    v9 = 16 * v11 + v10;
    if ( checkbox[i] != v9 )                    // 动态调试dump即可
    {
      puts("wrong flag!");
      system("pause");
      exit(0);
    }
  }
  puts("you get the flag!");
  system("pause");
  return 0;
}

1.2 分析

程序结构很清楚,输入字符后,进行16进制编码,与checkbox的值比较,相等即可

然后加上前面确定的6个字符,组成flag

1.3 解题

直接dump出来checkhbox

00403040  AD 00 00 00 46 00 00 00  1E 00 00 00 20 00 00 00  ....F....... ...
00403050  3C 00 00 00 79 00 00 00  75 00 00 00 B3 00 00 00  <...y...u.......
00403060  5E 00 00 00 52 00 00 00  79 00 00 00 60 00 00 00  ^...R...y...`...
00403070  CB 00 00 00 FE 00 00 00  B0 00 00 00 6C 00 00 00  ............l...

转换成小写,就是答案

2 666

2.1 题目

linux elf文件,ida打开

2.2 分析

2.2.1 主函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  ...

  memset(&s, 0, 0x1EuLL);
  printf("Please Input Key: ", 0LL);
  __isoc99_scanf("%s", &v5);
  encode(&v5, &s);                              // 对输入进行变换
  if ( strlen(&v5) == key )                     // 长度为0x12h
  {
    if ( !strcmp(&s, enflag) )                  // 变换后的s与enflag对比
      puts("You are Right");
    else
      puts("flag{This_1s_f4cker_flag}");
  }
  return 0;
}

2.2.2 encode函数

int __fastcall encode(const char *a1, __int64 a2)
{
  ...

  i = 0;
  v6 = 0;
  if ( strlen(a1) != key )
    return puts("Your Length is Wrong");
  for ( i = 0; i < key; i += 3 )
  {
    v5[i] = key ^ (a1[i] + 6);
    v4[i + 1] = (a1[i + 1] - 6) ^ key;
    v3[i + 2] = a1[i + 2] ^ 6 ^ key;
    *(_BYTE *)(a2 + i) = v5[i];
    *(_BYTE *)(a2 + i + 1LL) = v4[i + 1];
    *(_BYTE *)(a2 + i + 2LL) = v3[i + 2];
  }
  return a2;
}

整个加密过程如下:

三个一组,第一个字符+6异或key,第二个字符-6异或key,第三个字符异或6之后异或key。

写出对应的解密脚本即可

2.3 解题

flag=""
encode='izwhroz""w"v.K".Ni'
key=18
for i in range(0,18,3):
	flag=flag+chr((key^ord(encode[i]))-6)
	flag=flag+chr((key^ord(encode[i+1]))+6)
	flag=flag+chr((key^ord(encode[i+2]))^6)
print flag
#unctf{b66_6b6_66b}

3 vm

3.1 题目

一个linux下的elf文件,ida打开之后,找到main函数

3.2 分析

3.2.1 main函数

vmmain

3.2.2 sub_400C1E

__int64 __fastcall sub_400C1E(__int64 a1)
{
  __int64 result; // rax

  *(_QWORD *)a1 = off_4010A8;
  *(_QWORD *)(a1 + 8) = 0LL;
  *(_BYTE *)(a1 + 16) = 0;
  *(_BYTE *)(a1 + 17) = 0;
  *(_BYTE *)(a1 + 18) = 0;
  *(_DWORD *)(a1 + 20) = 0;
  *(_QWORD *)(a1 + 24) = 0LL;
  result = a1;
  *(_QWORD *)(a1 + 32) = 0LL;
  return result;
}

a1是跳转表的首地址,跳转表的内容如下

3.2.3 off_4010A8

rodata:0000000000401098 _ZTV2VM         dq 0                    ; offset to this
.rodata:00000000004010A0                 dq offset _ZTI2VM       ; `typeinfo for'VM
.rodata:00000000004010A8 off_4010A8      dq offset sub_400806    ; DATA XREF: sub_400C1E+8↑o
.rodata:00000000004010B0                 dq offset sub_400C7C
.rodata:00000000004010B8                 dq offset sub_400C9A
.rodata:00000000004010C0                 dq offset sub_400CB8
.rodata:00000000004010C8                 dq offset sub_400CD6
.rodata:00000000004010D0                 dq offset sub_400CFA
.rodata:00000000004010D8                 dq offset sub_400D1E
.rodata:00000000004010E0                 dq offset sub_400D42
.rodata:00000000004010E8                 dq offset sub_400D56
.rodata:00000000004010F0                 dq offset sub_400D70
.rodata:00000000004010F8                 dq offset sub_400D84
.rodata:0000000000401100                 dq offset sub_400DB0
.rodata:0000000000401108                 dq offset sub_400DDC
.rodata:0000000000401110                 dq offset sub_400E56
.rodata:0000000000401118                 dq offset sub_400ED0

每一个偏移量都对应一个函数。

3.2.4 虚拟机函数

signed __int64 __fastcall sub_400806(__int64 a1, __int64 a2, __int64 a3, __int64 a4)
{
  *(_QWORD *)(a1 + 8) = a2 + 9;
  *(_QWORD *)(a1 + 24) = a3;
  *(_QWORD *)(a1 + 32) = a4;
  while ( 2 )
  {
    switch ( **(unsigned __int8 **)(a1 + 8) )
    {
      case 0xA0u:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 8LL))(a1);
        continue;
      case 0xA1u:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 16LL))(a1);
        continue;
      case 0xA2u:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 24LL))(a1);
        *(_QWORD *)(a1 + 8) += 11LL;
        continue;
      case 0xA3u:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 32LL))(a1);
        *(_QWORD *)(a1 + 8) += 2LL;
        continue;
      case 0xA4u:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 40LL))(a1);
        *(_QWORD *)(a1 + 8) += 7LL;
        continue;
      case 0xA5u:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 48LL))(a1);
        ++*(_QWORD *)(a1 + 8);
        continue;
      case 0xA6u:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 56LL))(a1);
        *(_QWORD *)(a1 + 8) -= 2LL;
        continue;
      case 0xA7u:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 64LL))(a1);
        *(_QWORD *)(a1 + 8) += 7LL;
        continue;
      case 0xA8u:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 72LL))(a1);
        continue;
      case 0xA9u:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 80LL))(a1);
        *(_QWORD *)(a1 + 8) -= 6LL;
        continue;
      case 0xAAu:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 88LL))(a1);
        continue;
      case 0xABu:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 96LL))(a1);
        *(_QWORD *)(a1 + 8) -= 4LL;
        continue;
      case 0xACu:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 104LL))(a1);
        continue;
      case 0xADu:
        (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 112LL))(a1);
        *(_QWORD *)(a1 + 8) += 2LL;
        continue;
      case 0xAEu:
        if ( *(_DWORD *)(a1 + 20) )
          return 0LL;
        *(_QWORD *)(a1 + 8) -= 12LL;
        continue;
      case 0xAFu:
        if ( *(_DWORD *)(a1 + 20) != 1 )
        {
          *(_QWORD *)(a1 + 8) -= 6LL;
          continue;
        }
        return 1LL;
      default:
        puts("cmd execute error");
        return 0LL;
    }
  }
}

a1 + 8是虚拟机的核心,是一个分发器,根据它的值,选择哪条指令执行

(a1 + 24) = a3是预置的字符,输入字符经过运算之后进行比较。

(a1 + 32) = a4是输入的sn

3.2.5 跳转过程

a1 + 8的初值是a2 + 9,对应于case 0xA9,静态分析可以看出的,也可以通过动态调试得到,caseA9的内容为:

1.调用函数 a1+80ll
2.指明下一条的指令,应该是0XA9-6=0XA3

3.2.6 虚拟机整体流程

经过动态调试和静态分析,指令主要执行以下的case

9,3,5,6,4,B,7,E,2,D,F

将各个case中的代码提取出来,例如:

0xA9中offset +80LL的代码如下:

__int64 __fastcall sub_400D84(__int64 a1)
{
  __int64 result; // rax

  result = a1;
  *(_BYTE *)(a1 + 16) = *(_BYTE *)(*(_QWORD *)(a1 + 32) + *(unsigned __int8 *)(a1 + 18));
  return result;
}

a1 + 32代表输入,a1 + 18代表一个参数,写成伪代码如下:

a=*(str+c)

通过分析,流程如下,首先将字符的每一个值,先减去一个count,随后对另一个参数赋值b=b^a,a=0xcd,a=a^b, 判断是否与校验字符串中的值相等,最后b=a;循环检测每个字符。全部匹配则通过。

写成python如下:

todo


3.3 解题

穷举即可

flag=""
a=b=temp=c=0
check=[0xF4,0x0A,0xF7,0x64,0x99,0x78,0x9E,0x7D,0xEA,0x7B,0x9E,0x7B,0x9F,0x7E,0xEB,0x71,0xE8,0x00,0xE8,0x07,0x98,0x19,0xF4,0x25,0xF3,0x21,0xA4,0x2F,0xF4,0x2F,0xA6,0x7C]
for i in range(32):
	temp=b
	for j in range(32,128):
		b=temp
		a=j-i
		b=b^a
		c=b^0xcd
		if(c==check[i]):
			flag+=chr(j)
			b=check[i]
			break
print flag

4 babyre

4.1 题目

给出了一个linux 下的elf文件,ida打开

4.2 分析

总体的sn为 UNCTF{第一部分-第二部分}

4.2.1 第一部分sn

整个的过程如下:

查表替换后 0x82b37a02

第一轮 i=4 0xc6a80b9e 第二轮 i=5 0xD6FAE7F0

输入的16字符中的第一组4个字符^(左右移位(代换(4个字符)))放到第五组

输入的16字符中的第二组4个字符^(左右移位(代换(4个字符)))放到第六组 . . .

输入的16字符中的第二十六组4个字符^(左右移位(代换(4个字符)))放到第三十组 检验27-30组==[0xCC,0x22,0x7F,0x52,0x52,0x27,0xAA,0x48,0x34,0x72,0x5F,0xD0,0x0F,0x27,0x6B,0x39]

整体过程,四字符一组加密,然后进行26轮的循环检验,每轮四个字符组,由前面的计算后面的,最后的结果和预置字符比较,

sn的正向算法

#coding:utf-8
# 41 42 43 44
# 45 46 47 48 49 4A 4B 4C  4D 4E 4F 50 B7 1B EE 9B
# F9 54 93 DC E2 E4 8D 34  11 4F 31 BF 90 0B 5C 5A
# B3 3F 50 A7 F2 18 AF AF  71 B3 6E B0 CC 57 3A 1E
# F8 36 FA 83 9C 13 75 23  52 A7 0C 92 A9 42 E9 BD
# 1A D3 43 F1 A3 79 C2 C1  99 E5 F4 0D B3 7D 23 9E
# BB 9F 33 1B BD 4E 2C 60  02 77 EC E3 12 4C 33 E1
# 3F F6 7E 77 58 F1 10 BD  DF 43 CF B0 2D A0 2A 6F
# 02 03 C1 AA 
# sn=[0xCC,0x22,0x7F,0x52,0x52,0x27,0xAA,0x48,0x34,0x72,0x5F,0xD0,0x0F,0x27,0x6B,0x39]

import copy
def ror(s,n):
	return (s<<(32-n)|s>>n)&0xffffffff
def rol(s,n):
	return (s>>(32-n)|s<<n)&0xffffffff
sbox=[0x1B,0x5D,0x42,0x2B,0x0D,0x05,0x48,0xE6,0x35,0x16,0x9E,0xB5,0xBB,0xE3,0x24,0x0F,0x13,0xC0,0x59,0x96,0x5A,0x12,0x2B,0xE0,0x8F,0x21,0x8C,0x52,0xDE,0x92,0x12,0x84,0xA3,0xE2,0x6E,0x7B,0x76,0xA2,0x0F,0x51,0x93,0xA9,0x78,0xAB,0x5F,0x5E,0x16,0x82,0x72,0x82,0x26,0xD1,0x26,0xD4,0x09,0xBF,0x74,0xDA,0xA7,0x3E,0x99,0x02,0x65,0xC3,0xB3,0xAD,0xE0,0x5A,0xAB,0x7A,0x83,0x93,0x3F,0xA4,0x11,0x3D,0x8E,0x0D,0xDF,0x5A,0x71,0x08,0x3A,0xC8,0xF4,0x90,0x16,0x1B,0x88,0xC6,0x50,0x6F,0xD1,0xA4,0xB3,0x73,0x7B,0x82,0xBF,0xB2,0x5F,0x94,0xDE,0xCA,0x5A,0x5E,0xAB,0x25,0xBE,0x8C,0x1B,0x80,0x65,0x9E,0xEC,0x5A,0x37,0x2A,0x75,0x2C,0x2D,0xBA,0x56,0xD0,0xBA,0x3A,0xB6,0x94,0x81,0x70,0x87,0x75,0x3D,0x48,0x63,0x7D,0x52,0x81,0x39,0xB5,0x23,0xD4,0xD3,0xDD,0x4B,0xD9,0xB8,0x35,0xA3,0xCA,0x40,0x77,0x52,0x7C,0x9E,0x6C,0x42,0xD8,0x53,0x6F,0xEA,0x2E,0x0C,0x9A,0xF3,0x2A,0x6A,0xD5,0xEA,0x6B,0x93,0x2F,0x18,0x5C,0xBE,0x96,0xB4,0x26,0x0F,0xDB,0x9F,0x07,0x30,0xAF,0x93,0x34,0x27,0x8E,0x0A,0xCA,0x53,0xB7,0xC9,0x8F,0x9B,0x40,0x87,0x54,0x50,0x53,0x1E,0x55,0x06,0x04,0x87,0xC9,0x5E,0x78,0xA0,0x3F,0x66,0x08,0xB0,0x09,0x6E,0x83,0xE5,0x6C,0x23,0xE6,0x74,0x83,0x01,0xA4,0x7F,0x62,0x39,0x09,0x94,0x32,0xD3,0x88,0x93,0x61,0xC2,0xC6,0x61,0x6B,0x28,0xC7,0x61,0xDD,0xDB,0x90,0xA9,0xD5,0xD8,0x8A,0xA4,0xA0,0x65,0xC1,0x35,0x41,0xBA,0xCF,0x4A,0x47,0xCA,0xAF,0x51,0xE1,0x72,0x5A,0xBF,0x1E,0xB3,0x7A,0x80,0xF2,0x7A,0xCB,0x25,0xE6,0x98,0x96,0x1B,0x53,0x44,0xD8,0x3C,0xAC,0x12,0xB1,0x64,0x47,0x35]


# sn_init=[0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50]
# sn_change= copy.deepcopy(sn_init)
# for i in range(0,16,4):
# 	sn_change[i],sn_change[i+3]=sn_init[i+3],sn_init[i]
# 	sn_change[i+1],sn_change[i+2]=sn_init[i+2],sn_init[i+1]
# print sn_change
flag1=[]
s_flag=[]

sn_init=[0x43,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50]
for i in range(26):	
	sn_change= copy.deepcopy(sn_init)
	
	for j in range(0+i*4,16+i*4,4):
		# print 'sn_change:',sn_change,j
		# print 'sn_init:',sn_init
		sn_change[j],sn_change[j+3]=sn_init[j+3],sn_init[j]
		sn_change[j+1],sn_change[j+2]=sn_init[j+2],sn_init[j+1]
	
	for k in range(0+i*4,4+i*4):
		flag1.append(sn_change[k+1*4]^sn_change[k+2*4]^sn_change[k+3*4])
		s_flag.append(sbox[flag1[k]])

	temp=(s_flag[0+i*4]<<24)+(s_flag[1+i*4]<<16)+(s_flag[2+i*4]<<8)+(s_flag[3+i*4])
	temp_a=(sn_change[0+i*4]<<24)+(sn_change[1+i*4]<<16)+(sn_change[2+i*4]<<8)+(sn_change[3+i*4])

	res=ror(temp,6)^ror(temp,8)^rol(temp,10)^rol(temp,12)^temp_a
	sn_init.append(res&0xff)
	sn_init.append((res&0xff00)>>8)
	sn_init.append((res&0xff0000)>>16)
	sn_init.append((res&0xff000000)>>24)

	# print sn_init
temp_list=[]
for i in range(0,120):
	temp_list.append(hex(sn_init[i]))
# ['0x58L', '0xf1L', '0x10L', '0xbdL', '0xdfL', '0x43L', '0xcfL', '0xb0L', '0x2dL', '0xa0L', '0x2aL', '0x6fL', '0x2L', '0x3L', '0xc1L', '0xaaL']
# 2616073143
# d0,5f,72,34
# flag=[82, 127, 34, 204, 72, 170, 39, 82, 208, 95, 114, 52, 57, 107, 39, 15]
print temp_list

#input:flag='xxxxxxxxxxxxxxxx' 16个字符
#输出需要满足条件:temp_list最后的16个元素的值为:['0x52', '0x7f', '0x22', '0xcc', '0x48', '0xaa', '0x27', '0x52', '0xd0', '0x5f', '0x72', '0x34', '0x39', '0x6b', '0x27', '0xf']
#

一组测试值

:{_

todo

['0x41', '0x42', '0x43', '0x44', '0x45', '0x46', '0x47', '0x48', '0x49', '0x4a', '0x4b', '0x4c', '0x4d', '0x4e', '0x4f', '0x50', '0xb7L', '0x1bL', '0xeeL', '0x9bL', '0xf9L', '0x54L', '0x93L', '0xdcL', '0xe2L', '0xe4L', '0x8dL', '0x34L', '0x11L', '0x4fL', '0x31L', '0xbfL', '0x90L', '0xbL', '0x5cL', '0x5aL', '0xb3L', '0x3fL', '0x50L', '0xa7L', '0xf2L', '0x18L', '0xafL', '0xafL', '0x71L', '0xb3L', '0x6eL', '0xb0L', '0xccL', '0x57L', '0x3aL', '0x1eL', '0xf8L', '0x36L', '0xfaL', '0x83L', '0x9cL', '0x13L', '0x75L', '0x23L', '0x52L', '0xa7L', '0xcL', '0x92L', '0xa9L', '0x42L', '0xe9L', '0xbdL', '0x1aL', '0xd3L', '0x43L', '0xf1L', '0xa3L', '0x79L', '0xc2L', '0xc1L', '0x99L', '0xe5L', '0xf4L', '0xdL', '0xb3L', '0x7dL', '0x23L', '0x9eL', '0xbbL', '0x9fL', '0x33L', '0x1bL', '0xbdL', '0x4eL', '0x2cL', '0x60L', '0x2L', '0x77L', '0xecL', '0xe3L', '0x12L', '0x4cL', '0x33L', '0xe1L', '0x3fL', '0xf6L', '0x7eL', '0x77L', '0x58L', '0xf1L', '0x10L', '0xbdL', '0xdfL', '0x43L', '0xcfL', '0xb0L', '0x2dL', '0xa0L', '0x2aL', '0x6fL', '0x2L', '0x3L', '0xc1L', '0xaaL']

['0x43', '0x42', '0x43', '0x44', '0x45', '0x46', '0x47', '0x48', '0x49', '0x4a', '0x4b', '0x4c', '0x4d', '0x4e', '0x4f', '0x50', '0xb5L', '0x1bL', '0xeeL', '0x9bL', '0xfaL', '0x70L', '0x9fL', '0xd5L', '0xdL', '0x90L', '0xbdL', '0xcaL', '0xa5L', '0x55L', '0x9dL', '0x53L', '0x7fL', '0x32L', '0x35L', '0xe7L', '0xe3L', '0x1dL', '0x73L', '0x3aL', '0x71L', '0x29L', '0x17L', '0x87L', '0x8cL', '0x64L', '0x2aL', '0x30L', '0xd4L', '0xf6L', '0x67L', '0x34L', '0xd7L', '0x3dL', '0x3L', '0x7cL', '0xd6L', '0x2eL', '0xbbL', '0xa9L', '0xd6L', '0xe3L', '0x2aL', '0xcfL', '0xcaL', '0x99L', '0x47L', '0xdeL', '0x88L', '0x9bL', '0x4dL', '0x34L', '0x9eL', '0xb4L', '0x33L', '0x3fL', '0x9dL', '0xc1L', '0xc2L', '0xa0L', '0xcL', '0x3dL', '0xfdL', '0x35L', '0x3eL', '0xbL', '0x9cL', '0x5aL', '0x55L', '0x7aL', '0x2aL', '0x32L', '0xfbL', '0x8aL', '0x21L', '0x6eL', '0x6eL', '0xcL', '0x85L', '0xf0L', '0x32L', '0x21L', '0x6cL', '0xc8L', '0xeeL', '0x1aL', '0x6eL', '0x25L', '0xd6L', '0xc6L', '0xf6L', '0x72L', '0x6dL', '0x9fL', '0x4bL', '0x26L', '0x9aL', '0x43L', '0x49L', '0xbeL']

没有写粗求逆算法

todo

4.2.2 第二部分sn

-Wh4t_aB0ut_yoU233?

这个可以通过调试得到

todo

4.3 解题

5 Easy_Android

5.1 题目

Android软件,使用jeb打开

5.2 分析

安卓分析的思路为:查看MainActivity,调用函数,如果是MainActivity里面的函数,直接分析即可,如果有so中继承的函数,需要使用ida分析so库

5.2.1 MainActivity

package com.he.tian.easymix;

...
public class MainActivity extends AppCompatActivity {
    ...

    public MainActivity() {
        super();
        this.s = null;
    }

    static EditText a(MainActivity arg0) {
        return arg0.r;
    }

    static Toast a(MainActivity arg0, Toast arg1) {
        arg0.t = arg1;
        return arg1;
    }

    static Toast b(MainActivity arg0) {
        return arg0.t;
    }

    protected void onCreate(Bundle arg2) {
        ...
        this.s.setOnClickListener(new View$OnClickListener() {
            public void onClick(View arg4) {
               ...
                if(new d().a(MainActivity.a(this.a).getText().toString(), this.a.getResources().getString(0x7F0B0027), this.a.q)) {
                    v4 = this.a;
                    v1 = this.a;
                    v2 = "success";
                }
                else {
                    v4 = this.a;
                    v1 = this.a;
                    v2 = "fail";
                }

                MainActivity.a(v4, Toast.makeText(((Context)v1), ((CharSequence)v2), 0));
                MainActivity.b(this.a).show();
            }
        });
    }
}


经过一个判断之后,是success和fail,主要关注判断方法,类d中的a方法

5.2.2 d.a

package com.he.tian.easymix;

import android.widget.TextView;

public class d {
    byte[] a;

    public d() {
        super();
        this.a = new byte[]{1};
    }

    public boolean a(String true_flag, String fake_flag, TextView arg5) {
        fake_flag = "flag{this_is_a_fake_flag_ahhhhh}";
        if(true_flag.length() != fake_flag.length()) {
            return 0;
        }

        return new e().a(true_flag, fake_flag, arg5);
    }
}

第一个参数是从getext中得到的输入,第二个参数是一个虚假的flag,也是一个字符串,第三个参数是吐丝窗口。

首先判断了长度是否相等,长度为32个字节,不相等返回0,相等的话,return了一个函数,e类中的a函数

5.2.3 e.a

package com.he.tian.easymix;

import android.widget.TextView;

public class e {
    ...
    public e() {
        super();
        this.a = "2061e19de42da6e0de934592a2de3ca0";
        this.b = "a81813dabd92cefdc6bbf28ea522d2d1";
        this.c = "4b98921c9b772ed5971c9eca38b08c9f";
        this.d = "81773872cbbd24dd8df2b980a2b47340";
        this.e = "73b131aa8e4847d27a1c20608199814e";
        this.f = "bbd7c4e20e99f0a3bf21c148fe22f21d";
        this.g = "bf268d46ef91eea2634c34db64c91ef2";
        this.h = "0862deb943decbddb87dbf0eec3a06cc";
        this.i = "7a59d932e8184ae963c40a759cc38fec";
    }

    boolean a(String true_flag, String fake_flag, TextView arg12) {
        new b();
        String v12 = e.a(true_flag, fake_flag).toString().substring(0, 4);
        String v0 = e.a(true_flag, fake_flag).toString().substring(4, 8);
        String v2 = e.a(true_flag, fake_flag).toString().substring(8, 12);
        String v3 = e.a(true_flag, fake_flag).toString().substring(12, 16);
        String v4 = e.a(true_flag, fake_flag).toString().substring(16, 20);
        String v5 = e.a(true_flag, fake_flag).toString().substring(20, 24);
        String v6 = e.a(true_flag, fake_flag).toString().substring(24, 28);
        true_flag = e.a(true_flag, fake_flag).toString().substring(28, 32);
        fake_flag = b.a(v12, "utf8");
        v12 = b.a(v0, "utf8");
        v0 = b.a(v2, "utf8");
        v2 = b.a(v3, "utf8");
        v3 = b.a(v4, "utf8");
        v4 = b.a(v5, "utf8");
        v5 = b.a(v6, "utf8");
        true_flag = b.a(true_flag, "utf8");
        if((fake_flag.equals(this.a)) && (v12.equals(this.b)) && (v0.equals(this.c)) && (v2.equals(this.d)) && (v3.equals(this.e)) && (v4.equals(this.f)) && (v5.equals(this.g)) && (true_flag.equals(this.h))) {
            return 1;
        }

        return 0;
    }

    public static String a(String arg4, String arg5) {
        byte[] v4 = arg4.getBytes();
        byte[] v5 = arg5.getBytes();
        byte[] v0 = v4.length >= v5.length ? v4 : v5;  // 三目运算符,表达式为true是v4,false是v5,返回一个比较长的字符串
        if(v4.length >= v5.length) {
            v4 = v5;
        }

        v5 = new byte[v4.length];
        int v1;
        for(v1 = 0; v1 < v4.length; ++v1) {
            v5[v1] = ((byte)(v4[v1] ^ v0[v1]));
        }

        return new String(v5);
    }
}

流程,输入与原来的fake_flag异或,然后分8组,每组都经过b.a函数判断,然后将经过b.a的8组值与前面的8组md5作比较,都返回正确,才能通过。

5.2.4 b.a

package com.he.tian.easymix;

import java.security.MessageDigest;

public class b {
    private static final String[] a;

    static {
        b.a = new String[]{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
    }

    public b() {
        super();
    }

    public static String a(String arg2, String arg3) {
        String v1;
        String v0 = null;
        try {
            v1 = new String(arg2);
        }
        catch(Exception ) {
            return v0;
        }

        try {
            MessageDigest v2 = MessageDigest.getInstance("MD5");
            byte[] v2_1 = arg3 == null || ("".equals(arg3)) ? v2.digest(v1.getBytes()) : v2.digest(v1.getBytes(arg3));
            arg2 = b.a(v2_1);
        }
        catch(Exception ) {
            arg2 = v1;
        }

        return arg2;
    }

    public static String a(byte arg3) {
        int v3;
        if(arg3 < 0) {
            v3 = arg3 + 0x100;
        }

        return b.a[v3 / 16] + b.a[v3 % 16];
    }

    public static String a(byte[] arg3) {
        StringBuffer v0 = new StringBuffer();
        int v1;
        for(v1 = 0; v1 < arg3.length; ++v1) {
            v0.append(b.a(arg3[v1]));
        }

        return v0.toString();
    }
}

根据上面的双参数调用,判断有一个md5算法,返回值是参数arg2的md5,也就是异或后的md5。

5.2.5 总结

输入分8组,md5(每一组^fake_flag)=check_md5[8组]

5.3 解题

import hashlib
flag=""
count=0
s = "flag{this_is_a_fake_flag_ahhhhh}"

# a = "2061e19de42da6e0de934592a2de3ca0"
# b = "a81813dabd92cefdc6bbf28ea522d2d1"
# c = "4b98921c9b772ed5971c9eca38b08c9f"
# d = "81773872cbbd24dd8df2b980a2b47340"
# e = "73b131aa8e4847d27a1c20608199814e"
# f = "bbd7c4e20e99f0a3bf21c148fe22f21d"
# g = "bf268d46ef91eea2634c34db64c91ef2"
# h = "0862deb943decbddb87dbf0eec3a06cc"
# i = "7a59d932e8184ae963c40a759cc38fec"
check=["2061e19de42da6e0de934592a2de3ca0","a81813dabd92cefdc6bbf28ea522d2d1","4b98921c9b772ed5971c9eca38b08c9f","81773872cbbd24dd8df2b980a2b47340","73b131aa8e4847d27a1c20608199814e","bbd7c4e20e99f0a3bf21c148fe22f21d","bf268d46ef91eea2634c34db64c91ef2","0862deb943decbddb87dbf0eec3a06cc","7a59d932e8184ae963c40a759cc38fec"]
# print aaaaaaa
lib='0123456789abcdefghijklmnopqrstuvwxyz'
for a1 in lib:
	for a2 in lib:
		for a3 in lib:
			for a4 in lib:
				# print s[0],s[1],s[2],s[3]
				flag=chr((ord(a1)^ord(s[28])))+chr((ord(a2)^ord(s[29])))+chr((ord(a3)^ord(s[30])))+chr((ord(a4)^ord(s[31])))					
				md5=hashlib.md5(flag.encode('gb2312'))
				if(md5.hexdigest()==check[7]):
					print a1+a2+a3+a4

# flag=bd1d6ba7f1d3f5a13ebb0a75844cccfa

穷举即可,每次穷举四位

6 babyxor

6.1 题目

win32程序,ida打开,发现几乎没有函数,上下翻了一下,发现了2333段,判断有壳之类的

6.2 分析

6.2.1 start函数

void __usercall start(int a1@<eax>, int a2@<edx>, int a3@<ecx>, int a4@<ebx>, int a5@<ebp>, int a6@<edi>, int a7@<esi>)
{
 ...

  v9 = a3;
  v7 = 200704;
  v8 = byte_401000;
  do
  {
    *v8++ ^= 0x23u;
    --v7;
  }
  while ( v8 == 0 && v7 );
  sub_40C4A0(v9, a2);
}

刚开始就是一段异或算法,加密一段代码。可以通过idc脚本恢复,然后导出即可

6.2.2 sub_401600()

然后就是shift+F12找提示,找到了sub_401600

int sub_401600()
{
  int v0; // ST5C_4
  int v1; // ST6C_4
  int v2; // ST68_4
  int v3; // ST64_4
  int v4; // eax
  int v5; // ST60_4

  printf(&unk_4395F0, "世界上最简单的Xor");            // 输出
  sub_40107D(sub_40102D);
  if ( --dword_436274 < 0 )
  {
    sub_40BB80(&off_436270);
  }
  else
  {
    v0 = *(unsigned __int8 *)off_436270;
    off_436270 = (char *)off_436270 + 1;
  }
  v1 = sub_40108C(&unk_435DC0, 56);
  v2 = sub_401041(&unk_435DC0, &dword_435DF8, 56);
  v3 = sub_4096B0(100);
  v4 = sub_40BB00(v2);
  sub_40B7C0(v3, v2, v4);
  v5 = sub_4010C3(&unk_435DC0, v2, &dword_435E30, 56);
  sub_40101E(v1, v2, v5);
  return 0;
}

后面的没怎么看懂。。

todo

6.3 解题

todo

MISC

1 think

1.1 题目

给了一段python脚本,故意写成混淆形式的,有很多lambda函数

1.2 分析

稍微调整了一下格式

#
coding: utf - 8
print ""
"
____ ___ _ ___ _ _ _ _ ____ _____ _____
    | ___\ / _\ / | / _ \  | | | | \ | |/
___ | _ _ | ___ |
    __) | | | | | (_) | | | | | \ | | | | | | | _
    / __ / | | _ | | | \__, | | | _ | | | \ | | ___ | | | _ |
    | _____ | \___ / | _ | /_/\
___ / | _ | \_ | \____ | | _ | | _ |
    ""
"
(lambda __y, __operator, __g, __print: [
    [
        [
            [
                (__print(
                    "It's a simple question. Take it easy. Don't think too much about it."
                ), [(check(checknum), None)[1]
                    for __g['checknum'] in [(0)]
                ][0])[1]
                for __g['check'], check.__name__ in [(lambda checknum:
                    (lambda __l: [(lambda __after: (__print(
                                'Congratulation!'), (
                                __print(decrypt(key,
                                    encrypted)),
                                __after())[1])[1]
                            if __l['checknum']
                            else(__print('Wrong!'),
                                __after())[1])(lambda:
                            None)
                        for __l['checknum'] in [(checknum)]
                    ][0])(
                    {}), 'check')]
            ][0]
            for __g['decrypt'], decrypt.__name__ in [(lambda key,
                encrypted: (lambda __l: [
                    [(lambda __after, __sentinel, __items:
                        __y(lambda __this: lambda: (
                            lambda __i: [
                                [__this() for __l[
                                    'c'] in [
                                    (
                                        __operator
                                        .iadd(
                                            __l[
                                                'c'
                                            ],
                                            chr(
                                                (
                                                    ord(
                                                        __l[
                                                            'key'
                                                        ]
                                                        [
                                                            (
                                                                __l[
                                                                    'i'
                                                                ] %
                                                                len(
                                                                    __l[
                                                                        'key'
                                                                    ]
                                                                )
                                                            )
                                                        ]
                                                    ) ^
                                                    ord(
                                                        __l[
                                                            'encrypted'
                                                        ]
                                                        [
                                                            __l[
                                                                'i'
                                                            ]
                                                        ]
                                                        .decode(
                                                            'base64'
                                                        )
                                                        .decode(
                                                            'hex'
                                                        )
                                                    )
                                                )
                                            )
                                        ))
                                ]][0]
                                for __l['i'] in [
                                    (__i)
                                ]
                            ][0]
                            if __i is not __sentinel
                            else __after())(next(
                            __items,
                            __sentinel)))())(lambda:
                        __l['c'], [], iter(range(len(
                            __l['encrypted'])))) for __l[
                        'c'] in [('')]][0]
                    for __l['key'], __l['encrypted'] in [
                        (key, encrypted)
                    ]
                ][0])(
                {}), 'decrypt')]
        ][0]
        for __g['encrypted'] in [(['MTM=', 'MDI=', 'MDI=', 'MTM=',
            'MWQ=', 'NDY=', 'NWE=', 'MDI=', 'NGQ=',
            'NTI=', 'NGQ=', 'NTg=', 'NWI=', 'MTU=',
            'NWU=', 'MTQ=', 'MGE=', 'NWE=', 'MTI=',
            'MDA=', 'NGQ=', 'NWM=', 'MDE=', 'MTU=',
            'MDc=', 'MTE=', 'MGM=', 'NTA=', 'NDY=',
            'NTA=', 'MTY=', 'NWI=', 'NTI=', 'NDc=',
            'MDI=', 'NDE=', 'NWU=', 'MWU='
        ])]
    ][0]
    for __g['key'] in [('unctf')]
][0])((lambda f: (lambda x: x(x))(lambda y: f(lambda: y(y)()))),
    __import__('operator', level = 0), globals(), __import__(
        '__builtin__', level = 0).__dict__['print'])

大概看看,key为unctf,然后明文与key异或加密,加密后的结果是encrypted列表,base64 的形式,也就是base64编码,反解即可

1.3 解题

import base64
sn=['MTM=', 'MDI=', 'MDI=', 'MTM=', 'MWQ=', 'NDY=', 'NWE=', 'MDI=', 'NGQ=', 'NTI=', 'NGQ=', 'NTg=', 'NWI=', 'MTU=', 'NWU=', 'MTQ=', 'MGE=', 'NWE=', 'MTI=', 'MDA=', 'NGQ=', 'NWM=', 'MDE=', 'MTU=', 'MDc=', 'MTE=', 'MGM=', 'NTA=', 'NDY=', 'NTA=', 'MTY=', 'NWI=', 'NTI=', 'NDc=', 'MDI=', 'NDE=', 'NWU=', 'MWU=']
flag=''
key='unctf'
for i in range(len(sn)):
	flag+=chr(int(sn[i].decode('base64'),16)^ord(key[i%len(key)]))
print flag
print len(sn)
#flag{34a94868a8ad9ff82baadb326c513d40}

本文访问量: