Reverse

Simple Base-N

IDA打开,从pdb路径可以leek出现一些信息

可以看到有Base32的字样,估计算法里可能会出现相关信息

继续加载
简单重命名一下,注释上一眼就能看出来的结构

change函数里对Input做了变换,然后下面与一段字符串进行比较
注意这个地方break出去是继续跑下面的代码,并不是直接结束


从插件显示的花括号对应可以看到,break出去如果v7为true则会往下判断而不是直接到try a little bit harder那里return

因此上面的strcmp是个障眼法,实际上要在下面操作
分别查看sub_4012C0和sub_401310

做出一定整理后,4012C0如下所示

那个全局字符串变量估计就是base32的table了,没联想起来也不要紧,先放着就好
反正这里对全局变量进行了一些变换和修改,继续往下看

401310函数中的核心是另一个函数,长得比较乱,但是简单通过几个变量可以猜出来功能

&0x1f,取bin可以发现就是五位,这正符合base32的编码方法
“====”, 这个补齐方法也是base系的,而只有base32中才会出现四个等号
再根据之前看到的pdb信息,就基本可以确认该函数为base32_encode了

注意Table是跟正宗b32不同的,因为通过之前一个函数修改过表了,因此解密的时候也需要考虑这一点

main函数中将b32后的input与一串固定字符串比较,要求相等

解法显然就是做b32_decode后反change即可
这里的Table可以自己仿照运算生成,也可以直接用动态调试dump出Table来

然后b32的算法有点难找,我是直接找到python的lib里base64.py中b32decode函数的实现,扒过来以后改表即可

然后关于change变换函数,稍微理一理还是挺清晰的

针对大小写字母用不同的方法变换,要注意的是这里的%26会使得信息丢失,因此逆向的时候要做一下处理

逆change的脚本如下:
通过while判断是否为大/小写字母,然后不断累加26,将丢去的信息补回

得到Table"NoPqRsTuVwXyZaBcDeFgHiJkLm567234"后通过源码进行b32decode,最后再change逆运算一下即可

py2脚本

```
from __future__ import print_function
#! /usr/bin/env python"""RFC 3548: Base16, Base32, Base64 Data Encodings"""# Modified 04-Oct-1995 by Jack Jansen to use binascii module
# Modified 30-Dec-2003 by Barry Warsaw to add full RFC 3548 supportimport re
import struct
import binascii__all__ = [# Legacy interface exports traditional RFC 1521 Base64 encodings'encode', 'decode', 'encodestring', 'decodestring',# Generalized interface for other encodings'b64encode', 'b64decode', 'b32encode', 'b32decode','b16encode', 'b16decode',# Standard Base64 encoding'standard_b64encode', 'standard_b64decode',# Some common Base64 alternatives.  As referenced by RFC 3458, see thread# starting at:## http://zgp.org/pipermail/p2p-hackers/2001-September/000316.html'urlsafe_b64encode', 'urlsafe_b64decode',
]_translation = [chr(_x) for _x in range(256)]
EMPTYSTRING = ''def _translate(s, altchars):translation = _translation[:]for k, v in altchars.items():translation[ord(k)] = vreturn s.translate(''.join(translation))str = "NoPqRsTuVwXyZaBcDeFgHiJkLm567234"
_b32alphabet = {i:str[i] for i in range(32)}_b32tab = _b32alphabet.items()
_b32tab.sort()
_b32tab = [v for k, v in _b32tab]
_b32rev = dict([(v, (k)) for k, v in _b32alphabet.items()])def b32decode(s, casefold=False, map01=None):"""Decode a Base32 encoded string.s is the string to decode.  Optional casefold is a flag specifying whethera lowercase alphabet is acceptable as input.  For security purposes, thedefault is False.RFC 3548 allows for optional mapping of the digit 0 (zero) to the letter O(oh), and for optional mapping of the digit 1 (one) to either the letter I(eye) or letter L (el).  The optional argument map01 when not None,specifies which letter the digit 1 should be mapped to (when map01 is notNone, the digit 0 is always mapped to the letter O).  For securitypurposes the default is None, so that 0 and 1 are not allowed in theinput.The decoded string is returned.  A TypeError is raised if s wereincorrectly padded or if there are non-alphabet characters present in thestring."""quanta, leftover = divmod(len(s), 8)if leftover:raise TypeError('Incorrect padding')# Handle section 2.4 zero and one mapping.  The flag map01 will be either# False, or the character to map the digit 1 (one) to.  It should be# either L (el) or I (eye).if map01:s = _translate(s, {'0': 'O', '1': map01})if casefold:s = s.upper()# Strip off pad characters from the right.  We need to count the pad# characters because this will tell us how many null bytes to remove from# the end of the decoded string.padchars = 0mo = re.search('(?P<pad>[=]*)$', s)if mo:padchars = len(mo.group('pad'))if padchars > 0:s = s[:-padchars]# Now decode the full quantaparts = []acc = 0shift = 35for c in s:val = _b32rev.get(c)if val is None:raise TypeError('Non-base32 digit found')acc += _b32rev[c] << shiftshift -= 5if shift < 0:parts.append(binascii.unhexlify('%010x' % acc))acc = 0shift = 35# Process the last, partial quantalast = binascii.unhexlify('%010x' % acc)if padchars == 0:last = ''  # No characterselif padchars == 1:last = last[:-1]elif padchars == 3:last = last[:-2]elif padchars == 4:last = last[:-3]elif padchars == 6:last = last[:-4]else:raise TypeError('Incorrect padding')parts.append(last)return EMPTYSTRING.join(parts)# RFC 3548, Base 16 Alphabet specifies uppercase, but hexlify() returns
# lowercase.  The RFC also recommends against accepting input caser = "weNTDk5LZsNRHk6cVogqTZmFy2NRP7X4ZHLTBZwg"
r = b32decode(r)
print(r)
for i in r:v = ord(i)-ord('a')if(v>=0 and v<26):k = v+ord('T')while(k<=ord('a')):k += 26print(chr(k), end='')else:v = ord(i) - ord('A')if (v >= 0 and v < 26):k = (v + ord('4'))while(k<=ord('A')):k += 26print(chr(k), end='')else:print(i, end='')

flag{Y@u_Kn@W_b@s332_@Nd_r0t13}

Input your luncky number_string

main函数中通过cin接收输入,下面做了一大堆操作
但是通过对input变量的跟踪,可以发现都没有什么卵用
与输入无关,因此我们根本不需要去读,反正都是正向操作

只有箭头所指的部分才需要关注

于是查看sub_401100

v3 = _mm_cvtsi32_si128(input);
v4 = _mm_unpacklo_epi8(v3, v3);
v5 = _mm_shuffle_epi32(_mm_unpacklo_epi16(v4, v4), 0);

最开头这三个处理非常丑,要不挨个去查手册,要不就直接动调观察
汇编指令是三条

punpcklbw xmm0, xmm0
punpcklwd xmm0, xmm0
pshufd xmm1, xmm0, 0

全部是交叉赋值的,分别将1字节的input变为2字节、4字节、16字节

(试了OD和IDA都看不到XMM寄存器的值,最后用x32dbg才成功跟踪到)
下面两段循环实际上都是逐字节异或
因为第一段以XMM寄存器来操作,单位必须是16个字节,对于零头就无能为力了,于是使用第二段循环来逐字节操作
不知道是出题人故意设置的干扰还是编译器为了加速而优化出来的23333

那么下一个问题就是key啦
回头看参数a2对应的值,是0x401000+v6处的代码
观察加密后的HEX

(动调可知起始字节在0x89之后)

这里有大量的连续0x5A出现,在PE文件中通常会有大量的0x00作为填充,这里由于加密字节数太少所以没有用到上述的论据
不过连续三个0x5A通常一般是0x00000001之类的值加密得到的,因此还是只得一试的
之后还有0x7E、0x1E的出现频率比较高,但不连续,如果0x5A失败的话也可以试一试~

(实在不行也可以手动爆破,好几个交流的朋友都是一个一个试的,甚至还有一个小可爱是从255倒着试的23333333333333333333333333)

0x5A对应十进制的90,即NOP,这个数字还是比较有意义的233
输入以后便回显了flag(cin接受的是int类型,因此直接输入数字即可,而不用chr)

我们继续解密查看一下代码
解密IDC脚本

auto i;for(i=0;i<0x61;i++){PatchByte(0x401013+i, Byte(0x401013+i)^90);}


还是挺简单的,后面字节直接拷贝,前4个字节异或解密覆盖上去就完了

Interesting Pointer

前言

开始分析之前先表达一下对出题人和某春秋的意见
题目本身考点海星,可以算有意思的
但是没有考虑到多解,是出题人的失误

而某春秋死不认账,拿我提交的多解data强行跟正解data比较,找不同来一次一次限定范围就更没意思了
我知道正解才敢去质问你为什么长度一致的输入产生的flag还是不对,第一次提交多解讲要最短的输入,那理所当然最短的输入只有唯一的了。结果相同长度的输入还存在多解,请问我纠结浪费了几个小时谁来负责?
自己题目审核不严就算了,承认事故接受多解道个歉有这么难?处理态度一点都看不到大平台的体量

分析

一堆变量初始化直接放过,可以看到它读入data文件,所有内容放到了buff中
接着判断strlen和ftell给出的文件结尾是否相等,相等则结束
也就意味着文件中必须存在\x00来截断strlen

注意文件读取几乎晚于所有变量初始化,因此这里存在溢出点

处理过程如下

依次调用3个func,将返回值放在buff1、2、3中,要求buff[3]的值为0

3个Func的功能依次为exchange(buff[x], buff[y]), calc1(buff[x], buff[y]), calc2(buff[x], buff[y])

exchange固定
return 1
calc1具体过程为:
return abs(x + y) - abs(x) - abs(y) + 2
calc2具体过程为:
return abs(x) + abs(y) - abs(x + y) + 2

a-|a+1|+3
而三次函数的参数和返回值分别是
x = 3
y = 4
buff[1] = exchange(buff[x], buff[y])
buff[2] = calc1(buff[1], buff[2])
buff[3] = calc2(buff[2], buff[3])

这里我把x和y分离出来写的原因是,中间读入可以覆盖掉初始化,从而控制exchange的两个参数

首先如果不溢出的话,calc2想要返回0可以通过0x7fffffff和0x80000001来实现

由|x|+|y|>=|x+y|,即|x|+|y|-|x+y|+2>=2可知正常情况下无解
但是|x|+|y|-|x+y|+2==0x1 00000000却是有解的,令x、y互为相反数,则|x|==|y|==0x7fffffff

而calc1却不可能制造出这两个返回值,因此无解

calc1也很容易返回0, 有且仅有令两个操作数其中之一为-1即可

是吗?
令x, y都为正数, x+y=0x80000001则|x+y|=0x7fffffff,|x|+|y|-|x+y|正好就是2

返回buff[3]为0后,通过之前保存的buff[3]和buff[5]来得出flag
这里其实可以大概猜出来,关键的两个变量就是buff[3]和buff[5]了
然而比赛的时候我没注意这里23333导致从别的角度去考虑造成一堆多解

期望解

通过exchange交换calc1和calc2的位置,同时控制buff[3]为-1,则可满足条件
即构造data为
b"1"*(20+4*3) + b"\xff\xff\xff\xff" + b"\x07\x00\x00\x00" + b"\x08\x00\x00\x00"

生成flag的关键参数就是-1和8

非预期解

交换顺序非预期

这是最容易看到的多解,7和8两个数作为交换参数,当然8和7也是可行的,而生成flag提取的却只有最后一个参数
这个只有1种情况,试一下也可以接受

calc1的参数非预期

利用之前所说的calc1的溢出计算,使x和y都为正数的情况下和为0x80000001,则可同样使返回值为0
例如构造data为
b"1"*(20+4*3) + b"\xff\xff\xff\x7f" + b"\x07\x00\x00\x00" + b"\x08\x00\x00\x00"

通过交换过后的calc2来获得其中一个参数,由于exchange返回值只为1,从而可知calc2可获得的正数结果只有2
那么对应只要控制buff[3]为0x7fffffff即可

这样产生了2个多解

exchange的参数非预期

既然可以交换,凭什么非要交换calc1和calc2?
在buff前面有那么多可控字段,完全可以在其中填充上一个函数地址,然后通过exchange将其与calc2的指针变量交换,这个函数地址可以是calc1,还可以是随便什么返回0的函数

例如构造data为
b"\x00"*(20+4*3) + b"\xe8\x1f\x40\x00" + b"\x08\x00\x00\x00" + b"\x03\x00\x00\x00"

这里是利用strlen配合头部为’\0’从而返回0的示例

由于该程序没有ASLR,因此地址全部固定

这种情况下产生的多解就多了去了,一方面交换目标可以随意放置,即使在限制长度的情况下每个交换函数也有前面4个位置可以选择
而更关键的是此种情况下校验通过与否根本与第三个参数无关,因此生成的flag完全没有意义,硬要说的话每个buff[5]都有0x100000000个buff[3]可以组合

函数指针覆盖非预期

这个是最容易想到的,也是我最早提交的多解
反正都能溢出,凭什么还要通过exchange函数

例如构造data
b"1"*(20+4*3) + b"\xffffffff" + b"\x00"*(2*4) + b"\x97\x13\x40\x00" + b"\x97\x13\x40\x00"

直接将calc2处的指针修改为calc1
具体情况与上面exchange的情况相同,只不过不用通过exchange多此一举,缺点就是长度会长一些

180721 逆向-极客巅峰(Re)相关推荐

  1. 极客巅峰2021 web opcode

    文章目录 前言 一.源码泄露 二.分析源码 二.解题步骤 总结 更新 前言 打完了极客巅峰,说说感想:真就越来越菜了??签到都没出,直接0分,比刚入门那会儿还惨 下了两个pwn,一个 五六个libc+ ...

  2. 2020巅峰极客wp

    2020巅峰极客 巅峰极客是给开封市信网办做护网的时候打的比赛,所以比赛体验感并不好,简单写一下wp virus-re 代码分为三部分 以'-'为间隔,将flag的第一部分转换为整型数字,并且满足后项 ...

  3. 巅峰极客pwn wp

    Pwn gift 程序保护全开 程序功能: add:最多只能申请十次堆块,每次申请大小为0x60或0x100,往里写内容的时候是往user_data+0x10处写. delete:有UAF show: ...

  4. 巅峰极客2022wp

    巅峰极客2022 文章目录 巅峰极客2022 web babyweb ezWeb web babyweb 提示cbc padding oracle攻击,这是一个服务端的密码学漏洞,buu上做过原题[N ...

  5. 巅峰极客2022初赛 部分题解

    文章目录 Crypto point-power strange curve Misc easy_Forensic Lost 巅峰极客2022初赛,团队共解决7道题,合计2234分,排名第11位,晋级复 ...

  6. 2011年成都信息工程学院第二季极客大挑战逆向第三题Game破文

    [文章标题]: 2011年成都信息工程学院第二季极客大挑战逆向第三题Game破文 [文章作者]: JoyChou [软件名称]: Game [软件大小]: 176KB [下载地址]: http://w ...

  7. 2018巅峰极客writeup(Misc)

    原文地址:https://mistsatan.github.io/articles/2018-Peakgeek-Writeup-Misc.html 作为一个渣渣,带着去看各路神仙打架的想法报名了这次的 ...

  8. 巅峰极客第一场CTF部分writeup

    额,上午驾校学车,中午打了会儿安恒的月赛,就来看巅峰极客的题了.时间关系实力原因没做几个emmmm太菜了wa MISC-warmup-100pt 拿到一个bmp文件,套路走一波,右键查看属性emmm啥 ...

  9. [代码审计][PHAR]巅峰极客babyphp2学习压缩过滤器触发phar

    前言:我要当赛棍!!! 文章目录 序列化与反序列化 基本介绍 PHP反序列化漏洞原理 常用的魔法函数 __wakeup()绕过:CVE-2016-7124 __set:巅峰极客babyphp2 解决p ...

最新文章

  1. 阻碍职场发达的十种做法
  2. BUGLY集成升级空指针问题
  3. DNS服务器详解--------基础篇
  4. MyBatis 批量更新,批量更新
  5. java weblogic反序列化_Weblogic JAVA反序列化漏洞攻防搭建(3)
  6. 联想x250为什么这么贵_外媒:联想笔记本thinkpadX250如何联想thinkpadX250价格及评价...
  7. 凸优化第九章无约束优化 9.3 梯度下降方法
  8. HTML 标签参考手册:按字母顺序排列 HTML 标签
  9. Docker安装filebeat
  10. codeforces 407C Curious Array
  11. LINK : fatal error LNK1104: 无法打开文件“mfc71.lib”的原因一例
  12. 小米34寸2k显示器打开hdmi,同时开启144hdz和解决屏幕过白的问题
  13. 30分钟教你写出10分的淘宝标题
  14. Android获取一周每一天的日期
  15. Solr Replication
  16. android 光圈动画,Android 自定义View学习(4)波浪效果+光圈扩散效果
  17. 场景构图你知道多少?
  18. centos7.4下Jira6环境部署及破解操作记录(完整版)
  19. IDE硬盘 SCSI硬盘 SATA硬盘
  20. 画论38 董其昌《画禅室随笔》

热门文章

  1. 清华姚班学生ICML一人署名论文:协作学习的鲁棒性方法
  2. Invocation Target Exception调用目标异常可能是参数漏传
  3. 隔离电源和非隔离电源的区别,
  4. android--手机震动--Vibrator
  5. Html Table 合并单元格
  6. QImage图像格式解读
  7. COCO数据集格式解析
  8. 【Linux】syscall系统调用原理及实现
  9. android中bitmap压缩的几种方法详解
  10. 硬件工程师电路设计十大要点