吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4717|回复: 12
收起左侧

[CTF] 【转帖】UTCTF逆向题详解

[复制链接]
默小白 发表于 2019-3-18 14:31

转自:https://xz.aliyun.com/t/4393

UTCTF是上周末国外的一个CTF比赛,逆向题中有几道质量还不错,简单整理了一下供大家参考。

Super Sucure Authentication

这是一道Java逆向题。Java逆向题在CTF里比较少见,主要是因为Java反编译太容易,没有太多trick。
其中考察比较多的有反射和动态加载类等,这道题就是使用动态加载类对代码进行了保护。

首先使用Jd-gui反编译Authenticator类,可以发现flag被分成了8份,并分别通过8个Verifier类进行检查(Verifier0 - Verifier7):

if (!candidate.substring(0, 7).equals("utflag{")) {
  return false;
}
if (candidate.charAt(candidate.length() - 1) != '}') {
  return false;
}
StringTokenizer st = new StringTokenizer(candidate.substring(7, candidate.length() - 1), "_");
if (!Verifier0.verifyFlag(st.nextToken())) {
  return false;
}
if (!Verifier1.verifyFlag(st.nextToken())) {
  return false;
}
if (!Verifier2.verifyFlag(st.nextToken())) {
  return false;
}
if (!Verifier3.verifyFlag(st.nextToken())) {
  return false;
}
if (!Verifier4.verifyFlag(st.nextToken())) {
  return false;
}
if (!Verifier5.verifyFlag(st.nextToken())) {
  return false;
}
if (!Verifier6.verifyFlag(st.nextToken())) {
  return false;
}
if (!Verifier7.verifyFlag(st.nextToken())) {
  return false;
}

随便点开几个Verifier,发现逻辑都是一样的:

private static byte[] arr = jBaseZ85.decode(new String("+kO#^0000Q0ZE7[5DJ%U0u.ZH0S:wG0u.WG0S:CK00ifB2MU+E0v4*I...");
public static boolean verifyFlag(String paramString)
{
    Verifier0 localVerifier0 = new Verifier0();
    Class localClass = localVerifier0.defineClass("Verifier0", arr, 0, arr.length);
    Object localObject = localClass.getMethod("verifyFlag", new Class[] { String.class }).invoke(null, new Object[] { paramString });
    return ((Boolean)localObject).booleanValue();
}

可以看到这里使用了Java的动态加载类的方法,将一串常量字符串通过Base85解码,并加载为Verifier0类,并调用其中的verifyFlag函数。

这里我们直接将代码在Java IDE中执行,发现Base85解码后得到的字符串开头就是Class文件头CAFEBABE
将其保存到文件,然后用Jd-gui打开,发现代码跟上面基本一样,只是常量字符串发生了变化。由于文件有3MB之大,猜测之后还有很多层,于是需要写代码自动化脱壳。

这里我们需要做的就是从Class文件中提取出该字符串,使用Base85进行解码,然后再提取字符串,不断重复该过程。于是就需要从Class文件中提取字符串。

为了实现这个目标,我们可以考虑使用一些相关的库来Parse Class文件,但对于这种简单的字符串提取,也可以研究一下文件结构,手动把字符串从Class文件中提取出来。

首先观察到字符串的开头都是相同的+kO#,对应了Java Class文件的文件头,这样我们就可以定位到字符串开头。
但是实际上最后的字符串是由多个字符串拼起来的,即类似于new String("+kO#..") + new String("B2MU..") + ... + new String("F9Kl.."),体现在Class文件中就是两个字符串之间还有一段没有用的数据:

img

观察了一下可以发现,这段数据的长度是有规律的,基本上第一个间隔是13,后面的都是3,所以可以特判直接过滤掉。(我的特判写的比较丑陋就不放出来了,大家可以自己尝试实现)

最后得到8个Verifier的class文件,都是简单的编码或者加密:

Verifier0,异或加密:

img

Verifier1,字符串逆序:

img

Verifier2,hashCode,Java中爆破:

img

private static int[] encrypted = { 3080674, 3110465, 3348793, 3408375, 3319002, 3229629, 3557330, 3229629, 3408375, 3378584 };

    public static void verifyFlag()
    {
        for(int i = 0; i < 10; i++)
        {
            for(char c = 32; c < 127; c++)
                if (encrypted[i] == (c + "foo").hashCode()) {
                    System.out.print(c);
                }
        }
    }

Verifier3,凯撒移位:

img

Verifier4,简单数字运算:

img

Verifier5,MD5,直接查cmd5

img

Verifier6,SHA1,同上

img

Verifier7,flag直接送了

img

连接起来,得到完整flag:
utflag{prophets_anxious_demolition_animatronic_herald_fizz_stop_goodbye}

Simple python script

给出了python源代码:

flag = input("> ")
for i in range(0, len(flag), int((544+5j).imag)):
    inputs = []
    (lambda ねこ, _, __, ___, ____, _____, ネコ, q, k: getattr(ねこ, "extend")...
    temp = getattr(__import__("ha"+"".__class__.__name__[0]+"hl"+(3)...
    getattr(temp, "update")(getattr(flag[i:i + 5], "encode")("utf-8"))
    if getattr(__import__("difflib"), "SequenceMatcher")(None, getattr(getattr(temp, "hexdigest")(), "lower")(), getattr(inputs[i // 5], "decode")("utf-8").lower()).ratio() != 1.0:
        exit()

print("correct")

可以看到使用了多种混淆方式:

  1. getattr(class, method)就相当于class.method
  2. "".__class__.__name__[0]那些用来隐藏字符串(即"String"[0],"S")
  3. 最后的SequenceMatcher(...).ratio() == 1其实就是比较相等

于是整理出以下代码:

inputs = []
(lambda ... # 这段代码更新了inputs
temp = hashlib.new(... # 这里应该是使用了一种hashlib里的哈希
temp.update(flag[i:i + 5].encode("utf-8") ) # 对flag每5位做一次哈希
print(inputs[i // 5].decode("utf-8").lower()) # 这段代码是我新增的,因为最终与flag哈希值比较的和就是inputs[i // 5],所以打印出来
if temp.hexdigest().lower() == inputs[i // 5].decode("utf-8").lower(): # 原来应为!=,这里改成==防止exit
    exit()

运行可以打印出几个哈希值:

26d33687bdb491480087ce1096c80329aaacbec7
1c3bcf656687cd31a3b486f6d5936c4b76a5d749
11a3e059c6f9c223ce20ef98290f0109f10b2ac6
6301cb033554bf0e424f7862efcc9d644df8678d
95d79f53b52da1408cc79d83f445224a58355b13

在CMD5上可以查到其中一部分,哈希算法是SHA1,剩余的可以在hashtoolkit上查到,连接得到完整flag:
puppyp1zzaanimetoruskitty

MOV

IDA加载发现全是MOV指令,可以大概知道使用了Movfuscator进行了混淆处理。

对于复杂一些的Movfuscator程序,可以尝试根据程序中字符串等信息,配合trace工具和下断点来追踪程序流程,并猜测程序逻辑(一般来说逻辑不会特别复杂)。此外,也可以尝试使用Demovfuscator进行反混淆,运气好的话说不定会解得比较好看。

不过对于这道题,程序中搜不到字符串信息,运行也没有反应,在strace和ltrace时发现很多SIGILL信号:

img

于是尝试使用gdb进行调试,在发出SIGILL信号时,gdb会断住,这是可以观察到栈顶有一个u字符:

img

继续跟踪下去,发现每次SIGILL时栈顶都会添加一个字符,逐渐形成一个完整的flag:

img

utflag{sentence_that_is_somewhat_tangentially_related_to_the_challenge}

UTCTF adventure ROM

一道gameboy游戏逆向题,使用的工具是bgb(可以debug,非常方便)和IDA。

首先使用bgb运行游戏,可以看到有四个框,分别可以输入ABCD,输入错误会死掉,显示LOSER:

img

此外,地图上还有不可见的线(在题目描述中可知),碰到后也会死掉,显示DEAD:

img

大体了解游戏逻辑后,我们就可以开始逆向了。在IDA中打开,处理器选择z80(具体可以参考这份wp)。

首先搜索字符串,可以找到LOSER和DEAD:

img

搜索第一个DEAD的地址71E,可以找到判断撞线死亡的逻辑:

img

这里我们直接把这部分nop掉就不会再撞死了(注意这里的nop是\x00)

同样的方法搜索LOSER的地址568

img

找到了判断输入是否正确的判断,于是我们使用bgb在这里下断点:

img

可以看到我们的输入和正确值分别保存在ac寄存器中。
于是我们就可以反复运行,随便输入一个值,然后修改我们的输入值为正确值,并记录下来,即可获得完整flag:
AABDCACBBDBCDCAD

其他

剩下的几道题比较简单,有问题可以留言交流

官方源码

https://github.com/UTISSS/UTCTF/

点评

感觉这个很有意思,其中思路确实很巧妙  发表于 2019-3-20 14:40

免费评分

参与人数 4吾爱币 +1 热心值 +4 收起 理由
CalvinMcCain + 1 谢谢@Thanks!
WA自动机 + 1 谢谢 @Thanks!
菜鸡想学破解 + 1 我很赞同!
wulove + 1 + 1 鼓励转贴优秀软件安全工具和文档!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

qiuTruth 发表于 2019-3-19 23:22
老哥,打扰了,请教个问题。动态加载类这个反复的过程,它的终点是什么,是动态加载的新类不含有该string array的时候吗?
woshicn 发表于 2019-3-18 14:38
qiuTruth 发表于 2019-3-18 14:45
感谢楼主分享,刚好在复现,解决了我很多疑惑!
qdam 发表于 2019-3-18 17:12
对于拓展思路还是不错的
ts0001 发表于 2019-3-18 18:07
感谢楼主分享,有所得、谢谢!
一叶知夏 发表于 2019-3-18 21:26

对于拓展思路还是不错的
GaiaDC 发表于 2019-3-18 21:27
谢谢分享,参考学习一下
rickw 发表于 2019-3-19 07:16
多多分享
fentian_85 发表于 2019-3-19 07:52
学习学习
WA自动机 发表于 2019-3-19 08:57
学习了。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-1 07:26

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表