[buuctf.reverse] 131-135

本文详细介绍了FlareOn挑战赛中的几个解谜题目,包括FLEGGO、Tricky-Part2、5get_it和elfie。涉及逆向工程、字符串解密、隐写术等技术,通过分析代码和执行流程,最终揭示隐藏的密码和信息,如base64解码、ASCII码转换和Python反写函数等。
摘要由CSDN通过智能技术生成

目录

131_[FlareOn5]FLEGGO

132_[INSHack2018]Tricky-Part2

133_[FlareOn1]5get_it

134_[NPUCTF2020]芜湖

135_[FlareOn2]elfie


131_[FlareOn5]FLEGGO

打开附件是个压缩包,再打开是一堆压缩文件。这些文件大小差不多,估计是程序生成的,那么标志估计都是一样。

打开一个找到关键函数发现无法F5

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char ArgList[16]; // [esp+0h] [ebp-24h] BYREF
  __int128 v5; // [esp+10h] [ebp-14h]

  *(_OWORD *)ArgList = 0i64;
  v5 = 0i64;
  sub_4012D0();
  if ( sub_401050() )
  {
    sub_401510((wchar_t *)L"What is the password?\n", ArgList[0]);
    sub_4014C0((wchar_t *)L"%15ls", (char)ArgList);          //输入数据
    if ( sub_401240(ArgList) )                               //检查
    {
      sub_4010B0(ArgList);
      if ( sub_401100() )
      {
        sub_401510((wchar_t *)L"Everything is awesome!\n", ArgList[0]);
        sub_401510((wchar_t *)L"%s => %s\n", (char)&unk_4043A0);
        return (unsigned __int16)word_4043CA;
      }
      else
      {
        sub_401510((wchar_t *)L"Oh look a rainbow.\n", ArgList[0]);
        return -1;
      }
    }
    else
    {
      sub_401510((wchar_t *)L"Go step on a brick!\n", ArgList[0]);   //报错
      return -1;
    }
  }
  else
  {
    sub_401510((wchar_t *)L"I super hate you right now.\n", ArgList[0]);
    return -1;
  }
}

运行一下,基本确认

C:\buuctf.reverse\131_[FlareOn5]FLEGGO\file>1JpPaUMynR9GflWbxfYvZviqiCB59RcI.exe
What is the password?
oooooooooo
Go step on a brick!

看下汇编

 很简单就是输入和一个串比较。由于windows上数据是以UTF-16存放的,所以ASCII码应该是存成A\0B\0这样的格式。输入IconManSucks并不正确,然后瞎找也找不到,看WP说是跟着输入Brick找,找到两个BRICK,,在第2个BRICK后是密码,每个文件位置都相同。在IDA中是看不到的,因为他只出现自己能理解的东西,理解不了的就写成?了。

 输入密码后会生成一个图片文件以及一个字母。图片左上角是一个数字

 很明显这个数字是这个字母在flag中的位置。将图版排下序然后对照输入字母将其排成flag。由于flag很长所以,只能对图片排序了,不然一会就乱了。

import os
from subprocess import Popen,PIPE

files = os.listdir('./file')
for f in files:
    if f[-4:] == '.exe':
        data = open("./file/"+f, 'rb').read()[0x2ab0: 0x2ab0+0x20].replace(b'\0',b'')
        #print(f, data, end=' ')
        p = Popen("./file/"+f, stdin=PIPE, stdout=PIPE)
        p.stdin.write(data)
        p.stdin.close()
        p.stdout.readline()
        p.stdout.readline()
        msg = p.stdout.readline()
        p.stdout.close()
        print(f, msg)
        #break

#把输入内容整理成文件名:字符 的字典
dit = {
'65141174' : 'w' ,
'85934406' : 'm' ,
'67782682' : 'm' ,
'75072258' : 'r' ,
'16544936' : 'e' ,
'67322218' : '_' ,
'58770751' : 'o' ,
'64915798' : '3' ,
'88763595' : 'e' ,
'18376743' : '_' ,
'36870498' : 'm' ,
'72501159' : 'c' ,
'47619326' : 'p' ,
'70037217' : 'm' ,
'18309310' : '@' ,
'15566524' : 'e' ,
'82100368' : 'm' ,
'60075496' : 's' ,
'71290032' : 'a' ,
'33718379' : '.' ,
'42255131' : 't' ,
'16295588' : 'a' ,
'61333226' : 'f' ,
'13147895' : 'w' ,
'16785906' : '4' ,
'80333569' : 'o' ,
'37723511' : 'n' ,
'44958449' : '_' ,
'30171375' : 's' ,
'72263993' : 'h' ,
'82236857' : 'e' ,
'33098947' : '_' ,
'33662866' : 'r' ,
'47893007' : '_' ,
'61006829' : 'l' ,
'89295012' : '0' ,
'87730986' : '0' ,
'65626704' : '3' ,
'72562746' : '-' ,
'36494753' : '0' ,
'79545849' : 's' ,
'63223880' : 'a' ,
'51227743' : 'a' ,
'73903128' : 'u' ,
'52817899' : 'n' ,
'19343964' : 'o' ,
'12268605' : 's' ,
'47202222' : 'n' }

#将排好序的(文件名前面加序号)文件名dir整理成数组
a = [
'67782682',
'80333569',
'75072258',
'64915798',
'44958449',
'16295588',
'65141174',
'82236857',
'30171375',
'36494753',
'70037217',
'65626704',
'33098947',
'42255131',
'72263993',
'16785906',
'37723511',
'67322218',
'71290032',
'47202222',
'18376743',
'63223880',
'13147895',
'16544936',
'60075496',
'87730986',
'82100368',
'88763595',
'47893007',
'47619326',
'89295012',
'79545849',
'12268605',
'73903128',
'85934406',
'18309310',
'61333226',
'61006829',
'51227743',
'33662866',
'15566524',
'72562746',
'19343964',
'52817899',
'33718379',
'72501159',
'58770751',
'36870498']
flag = ''
for i in a:
    flag+=dit[i]
print(flag)
#flag{mor3_awes0m3_th4n_an_awes0me_p0ssum@flare-on.com}

132_[INSHack2018]Tricky-Part2

这个很简单,上来就是对比

__int64 __fastcall check(__int64 a1)
{
  int i; // [rsp+1Ch] [rbp-D4h]
  int v3[52]; // [rsp+20h] [rbp-D0h]

  v3[0] = 73;
  v3[1] = 78;
  v3[2] = 83;
  v3[3] = 65;
  v3[4] = 123;
  v3[5] = 89;
  v3[6] = 48;
  v3[7] = 117;
  v3[8] = 95;
  v3[9] = 115;
  v3[10] = 104;
  v3[11] = 48;
  v3[12] = 117;
  v3[13] = 108;
  v3[14] = 100;
  v3[15] = 95;
  v3[16] = 107;
  v3[17] = 110;
  v3[18] = 48;
  v3[19] = 119;
  v3[20] = 95;
  v3[21] = 116;
  v3[22] = 104;
  v3[23] = 52;
  v3[24] = 116;
  v3[25] = 95;
  v3[26] = 49;
  v3[27] = 95;
  v3[28] = 99;
  v3[29] = 52;
  v3[30] = 110;
  v3[31] = 95;
  v3[32] = 116;
  v3[33] = 114;
  v3[34] = 49;
  v3[35] = 99;
  v3[36] = 107;
  v3[37] = 95;
  v3[38] = 121;
  v3[39] = 48;
  v3[40] = 117;
  v3[41] = 114;
  v3[42] = 95;
  v3[43] = 100;
  v3[44] = 51;
  v3[45] = 98;
  v3[46] = 117;
  v3[47] = 103;
  v3[48] = 103;
  v3[49] = 51;
  v3[50] = 114;
  v3[51] = 125;
  for ( i = 0; i <= 51; ++i )
  {
    if ( *(char *)std::string::operator[](a1, i) != v3[i] )
      return 0LL;
  }
  return 1LL;
}

直接输出就行

a = [73,78,83,65,123,89,48,117,95,115,104,48,117,108,100,95,107,110,48,119,95,116,104,52,116,95,49,95,99,52,110,95,116,114,49,99,107,95,121,48,117,114,95,100,51,98,117,103,103,51,114,125]
print(bytes(a))
#INSA{Y0u_sh0uld_kn0w_th4t_1_c4n_tr1ck_y0ur_d3bugg3r}
#flag{Y0u_sh0uld_kn0w_th4t_1_c4n_tr1ck_y0ur_d3bugg3r}

133_[FlareOn1]5get_it

这个一上来就给每个字符switch调用一个函数

const char *sub_10009EB0()
{
  const char *result; // eax
  int v1; // [esp+0h] [ebp-8h]
  __int16 i; // [esp+4h] [ebp-4h]

  for ( i = 8; ; ++i )
  {
    if ( i > 222 )
      return 0;
    if ( GetAsyncKeyState(i) == -32767 )
      break;
LABEL_2:
    ;
  }
  switch ( i )
  {
    case '\'':
      return sub_100093B0();
    case '(':
      return sub_100093C0();
    case ')':
      return sub_100093D0();
    case '*':
      return sub_100093E0();
    case '+':
      return sub_100093F0();
    case ',':
      return sub_10009400();
    case '-':
      return sub_10009410();
    case '.':
      return sub_10009420();
    ...

似乎每个函数都一样直接返回字符,一个个点下来还确实有不一样的

const char *sub_10009440()
{
  if ( dword_10019460 <= 0 )
  {
    if ( dword_100194A4 <= 0 )
    {
      _cfltcvt_init();
    }
    else
    {
      dword_100194A4 = 0;
      dword_100194A8 = 1;
    }
  }
  else
  {
    dword_10019460 = 0;
    dword_10019464 = 1;
  }
  return "0";
}

这个函数进行了两次比较。然后一个个点函数,有些1次有些多次,把这些比较放一起

9460,94a4:0
9498,94b0:5
94b4,94c4,94d4:a
94f4:c
9478,948c,94d0,94e8:d
94ac,94cc:e
94bc:f
9464,9468,9474:g
94dc:h
946c:i
94a8:k
7000,94c0:l
94fc:m
9470,94e4:n
947c,9490,94e0,94ec,94f8:o
9488,94a0,94c8:r
94d8:s
9480,9494,949c,94b8,94f0:t
9484:u

似乎flarecom这些都出现了,按时位置进行排序(出现多次的排多次,有重复使用的字符)得到flag,把dot,dash,at改为符号,但怎么也不对。网上搜到u是大写

a = '''
9460,94a4:0
9498,94b0:5
94b4,94c4,94d4:a
94f4:c
9478,948c,94d0,94e8:d
94ac,94cc:e
94bc:f
9464,9468,9474:g
94dc:h
946c:i
94a8:k
7000,94c0:l
94fc:m
9470,94e4:n
947c,9490,94e0,94ec,94f8:o
9488,94a0,94c8:r
94d8:s
9480,9494,949c,94b8,94f0:t
9484:u
'''
dic = {}
a = a.split('\n')
for i in a:
    if i == '':
       continue 
    b = i.split(':')
    c = b[0].split(',')
    for j in c:
        dic[j] = b[1]
print(dic)
print(''.join([dic[i] for i in sorted(dic.keys())]))
#l0ggingdoturdot5tr0ke5atflaredashondotcom
#flag{l0gging.ur.5tr0ke5@flare-on.com)
#flag{l0gging.Ur.5tr0ke5@flare-on.com}

134_[NPUCTF2020]芜湖

题目没有输入,运行时输入一首散文诗

眼前重复的风景,
渐渐模糊了约定,
星空下流浪的你,
仍然秘密的距离,
温度消失的瞬间,
无法触摸的明天,
没有引力的世界,
没有脚印的光年,
还在等着你出现,
日日夜夜自转的行星,
到处遮满别人的背影,
让风吹散混乱的呼吸,
快快清醒~
静静照亮原来的自己,
天空洒满忽然的光明,
眼中只要绚烂的天际,
再飞行!
我勇敢地抬起头,
看着茫茫的宇宙,
多少未知的星球,
有没有通向未来路口,
亲爱的伙伴,
让我们一起点燃,
勇气和信念,
在遥远的天边,
银河边缘,
有一片神奇的彩虹海,
和我一起冒险,
飞向另一个世界,
在遥远的天边,
银河边缘,
有一片神奇的彩虹海,
和我一起冒险,
飞向另一个世界,
super magic world~~

用ida打开看就是经过处理以后base64解码然后就输出了

unsigned __int64 o00oo0o0o0o(void)
{
  __int64 v0; // rax
  bool v2; // [rsp+2h] [rbp-4Eh]
  char v3; // [rsp+3h] [rbp-4Dh]
  int i; // [rsp+4h] [rbp-4Ch]
  int j; // [rsp+8h] [rbp-48h]
  int k; // [rsp+Ch] [rbp-44h]
  char v7[40]; // [rsp+10h] [rbp-40h] BYREF
  unsigned __int64 v8; // [rsp+38h] [rbp-18h]

  v8 = __readfsqword(0x28u);
  for ( i = 0; i <= 34; ++i )
  {
    for ( j = 0; j < o000O0ooo0ooOoOo[i]; ++j )
    {
      v3 = o0ooOo0oo0O[42 * i + j];
      v2 = 0;
      for ( k = 0; k <= 7; ++k )
        v2 = Oo0O((v3 >> (7 - k)) & 1, (97 >> (7 - k)) & 1) ^ (2 * v2);
      std::string::operator+=((char *)&oOoOo00[abi:cxx11] + 32 * i, v2);
    }
    o0o0OO((__int64)v7, (__int64)&oOoOo00[abi:cxx11] + 32 * i);// base64解码
    v0 = std::operator<<<char>(&std::cout, v7);
    std::ostream::operator<<(v0, &std::endl<char,std::char_traits<char>>);
    std::string::~string(v7);
  }
  std::ostream::operator<<(&std::cout, &std::endl<char,std::char_traits<char>>);
  return __readfsqword(0x28u) ^ v8;
}

base64的多句,然后跟进行发现相同的一句许但base64的值不同。应该是base64隐写,网上下个小程序,解下

from pwn import *

data = open('./wuhu', 'rb').read()

def o0o0o(a1, a2):
    return (a1 & a2) == 0
def Oo0O(a1, a2):
    v2 = o0o0o(a1, a2)
    v3 = o0o0o(a1, v2)
    v4 = o0o0o(a1, a2)
    v5 = o0o0o(a2, v4)
    v6 = o0o0o(v5, v3)
    return v6

s = ''
for i in range(35):
    tmp = ''
    for j in range(u32(data[0x46a0 + i*4: 0x46a0 + i*4+4])):
        v3 = data[0x40e0 + 42*i + j]
        v2 = 0
        for k in range(8):
            v2 = Oo0O((v3 >> (7 - k)) & 1, (97 >> (7 - k)) & 1) ^ (2 * v2)
        tmp += chr(v2)
    print(tmp)
    s+=tmp+'\n'
open('out1.txt', 'w').write(s)

base64隐写工具

import base64
path = input("请输入加密文件路径\n")
file = open(path)
a = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
aaa = ''
while True:
    text = file.readline()  # 只读取一行内容
    # 判断是否读取到内容
    text = text.replace("\n", "")
    if not text:
        break
    if text.count('=') == 1:
        aaa = aaa + \
            str('{:02b}'.format((a.find(text[len(text)-2])) % 4))
    if text.count('=') == 2:
        aaa = aaa + \
            str('{:04b}'.format((a.find(text[len(text)-3])) % 16))
file.close()
t = ""
ttt = len(aaa)
ttt = ttt//8*8
for i in range(0,ttt,8):
    t = t + chr(int( aaa[i:i+8],2))
print(t)

结果

C:\buuctf.reverse\134_[NPUCTF2020]芜湖>py \tools\base64隐写.py
请输入加密文件路径
out1.txt
npuctf{Fly1ng!!!}

135_[FlareOn2]elfie

先用密码flare 解压后,010打开是exe文件MZ 修改扩展名为exe

发现图标是py的文件,用工具解包

py \tools\pyinstxtractor.py elfie.exe

用010打开修改头里发现没有头标记,且文件几乎都是ascii码

 把开头和结尾的一点乱码删掉后,把尾部的exec改为print得到py文件

from PySide import QtGui, QtCore
import base64
OOO00O00OO0OO000OOOO00000000OOO0 = ''.join((OOOO00OO0OOO000OOOO00O00O0OOOOOO for OOOO00OO0OOO000OOOO00O00O0OOOOOO in reversed

用到反写这个函数,然后从尾部可以看到反写的flag

class OO00O0O00OOO00OOOO0O00O0000OOOOO(getattr(QtGui, 'tidEtxeTQ'[::-1])):
    def __init__(self, OO0O0O0O0OO0OO00000OO00O0O0000O0, OO00O00O00OO00OO0OO0OO000O0O00OO, OO0OOO00O00O0OO00000OO0000OO0OOO):
    super(OO00O0O00OOO00OOOO0O00O0000OOOOO, self).__init__(OO0O0O0O0OO0OO00000OO00O0O0000O0)
    self.OO0O0O0O0OO0OO00000OO00O0O0000O0 = OO0O0O0O0OO0OO00000OO00O0O0000O0
    self.OO00O00O00OO00OO0OO0OO000O0O00OO = OO00O00O00OO00OO0OO0OO000O0O00OO
    self.OO0OOO00O00O0OO00000OO0000OO0OOO = OO0OOO00O00O0OO00000OO0000OO0OOO
    self.OOOOOOOOOO0O0OOOOO000OO000OO0O00 = False
def O000OOOOOO0OOOO00000OO0O0O000OO0(self):
        O0O0O0000OOO000O00000OOO000OO000 = getattr(self, 'txeTnialPot'[::-1])()
        if (O0O0O0000OOO000O00000OOO000OO000 == ''.join((OO00O00OOOO00OO000O00OO0OOOO0000 for OO00O00OOOO00OO000O00OO0OOOO0000 in reversed('moc.no-eralf@OOOOY.sev0000L.eiflE')))):
        self.OO0O0O0O0OO0OO00000OO00O0O0000O0.setWindowTitle('!sseccus taerg'[::-1])
        self.OOOOOOOOOO0O0OOOOO000OO000OO0O00 = True
        self.OO0O0O0O0OO0OO00000OO00O0O0000O0.setVisible(False)
        self.OO0O0O0O0OO0OO00000OO00O0O0000O0.setVisible(True)
print('moc.no-eralf@OOOOY.sev0000L.eiflE'[::-1])
#flag{Elfie.L0000ves.YOOOO@flare-on.com}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值