1: X

主要逻辑在X.dll中,直接使用dnspy进行反编译

可以看到当为42的时候,为判定条件

image-20231115110005571

2: ItsOnFire

是一个apk的文件,直接使用jeb进行反编译,找来找去,发现主要的函数在f b中,实现的AES

image-20231115112252566

代码贴出来 主要的地方:

    private final long a(byte[] arr_b) {
        CRC32 cRC320 = new CRC32();
        cRC320.update(arr_b);
        return cRC320.getValue();
    }

		private final byte[] b(String s, byte[] arr_b, SecretKeySpec secretKeySpec0, IvParameterSpec ivParameterSpec0) {
        Cipher cipher0 = Cipher.getInstance(s);
        cipher0.init(2, secretKeySpec0, ivParameterSpec0);
        byte[] arr_b1 = cipher0.doFinal(arr_b);
        Intrinsics.checkNotNullExpressionValue(arr_b1, "cipher.doFinal(input)");
        return arr_b1;
    }

    private final File c(int v, Context context0) {
        Resources resources0 = context0.getResources();
        Intrinsics.checkNotNullExpressionValue(resources0, "context.resources");
        byte[] arr_b = this.e(resources0, v);
        byte[] arr_b1 = this.d(context0).getBytes(Charsets.UTF_8);
        Intrinsics.checkNotNullExpressionValue(arr_b1, "this as java.lang.String).getBytes(charset)");
        SecretKeySpec secretKeySpec0 = new SecretKeySpec(arr_b1, "AES");
        String s = "AES/CBC/PKCS5Padding";
        Intrinsics.checkNotNullExpressionValue(s, "context.getString(R.string.alg)");
        String s1 = "abcdefghijklmnop";
        Intrinsics.checkNotNullExpressionValue(s1, "context.getString(\n     …             R.string.iv)");
        byte[] arr_b2 = s1.getBytes(Charsets.UTF_8);
        Intrinsics.checkNotNullExpressionValue(arr_b2, "this as java.lang.String).getBytes(charset)");
        byte[] arr_b3 = this.b(s, arr_b, secretKeySpec0, new IvParameterSpec(arr_b2));
        File file0 = new File(context0.getCacheDir(), "playerscore.png");
        FilesKt__FileReadWriteKt.writeBytes(file0, arr_b3);
        return file0;
    }

    private final String d(Context context0) {
        String s = "https://flare-on.com/evilc2server/report_token/report_token.php?token=";
        Intrinsics.checkNotNullExpressionValue(s, "context.getString(R.string.c2)");
        String s1 = "wednesday";
        Intrinsics.checkNotNullExpressionValue(s1, "context.getString(R.string.w1)");
        String s2 = s.subSequence(4, 10) + s1.subSequence(2, 5);
        Intrinsics.checkNotNullExpressionValue(s2, "StringBuilder().apply(builderAction).toString()");
        byte[] arr_b = s2.getBytes(Charsets.UTF_8);
        Intrinsics.checkNotNullExpressionValue(arr_b, "this as java.lang.String).getBytes(charset)");
        long v = this.a(arr_b);
        String s3 = v + v;
        Intrinsics.checkNotNullExpressionValue(s3, "StringBuilder().apply(builderAction).toString()");
        return StringsKt___StringsKt.slice(s3, new IntRange(0, 15));
    }

上面的代码可以知道:

  • iv = “abcdefghijklmnop”

  • AES加密 模式CBC

  • 函数a为CRC加密

  • key为s = “https://flare-on.com/evilc2server/report_token/report_token.php?token=" 的 4到10位,s1 = “wednesday” 的 2到5位,切割后,得到arr_b后进行crc

  • import binascii
    
    s = "https://flare-on.com/evilc2server/report_token/report_token.php?token="
    s1 = "wednesday"
    
    # 从字符串构建字节对象
    s_bytes = s.encode()
    s1_bytes = s1.encode()
    
    # 构建新字符串s2
    s2 = s_bytes[4:10] + s1_bytes[2:5]
    
    print(s2)
    
    # 计算CRC32值并进行位运算,得到无符号整数
    v = binascii.crc32(s2) & 0xFFFFFFFF
    
    print(v)
    
    4508305374508305
    
  • key = 4508305374508305

#iv = "abcdefghijklmnop"
#key = 4508305374508305
#AES CBC

from Crypto.Cipher import AES
from hexdump import hexdump

iv = b'abcdefghijklmnop'
key = b'4508305374508305'
file = 'iv.png'

cipher = AES.new(key, AES.MODE_CBC, iv)
with open(file, 'rb') as bin:
    enc = bin.read()

data = cipher.decrypt(enc)

hexdump(data)

with open('right_' + file, 'wb') as bin:
    bin.write(data)

image-20231115133930819

3: mypassion

Part1: 01cdeR@brUc3E

image-20231115142140701

第一个判断条件为 参数第一个的第一个字符等于0x30,并且第二个字母 左移4 + 第三个字母 等于需要等于0x127

for i in range(0x20, 0x7f):
    for j in range(0x20, 0x7f):     
        if j + i * 4 == 0x127:
            print(chr(i), chr(j))       

爆破出来的序列是:

+ {
, w
- s
. o
/ k
0 g
1 c
2 _
3 [
4 W
5 S
6 O
7 K
8 G
9 C
: ?
; ;
< 7
= 3
> /
? +
@ '
A #

一会再看看 选择哪个序列,目前根据上面所有的条件知道 1 2 3 6位的数据

image-20231115144029479

这里v12 代表了后续的VirtualAlloc申请的属性,后面需要执行的话 只能是PAGE_EXECUTE_READWRITE所以第7位的为0x40

image-20231115144345461

申请完内存后,可以发现,我们的memset清空后,将shellcode写入了申请的空间并且执行

但是其中的0xC的位置,由于是我们的输入会导致shellcode的不正确

image-20231115145503396

这个位置自己修改了一下,为45(E)的时候为正常

image-20231115150127896

目前的参数修改为:01cdeR@hijklEnopqrstuvwxyz

image-20231115155038909

这里有进行比较brUc3 得到第一部分 01cdeR@brUc3E

Part2: file.bin

image-20231115171451340

会在该文件目录创建一个文件

image-20231115171534205

暂定 输入为 01cdeR@brUc3E/file.bin/

写入文件的是一个加密的数据,还暂时不知道是什么,下面对shellcode进行解密了,我们直接dump出来

image-20231115172140702

image-20231115172331553

48 89 5C 24 10 48 89 74 24 18 57 48 83 EC 20 48 8B 81 08 01 00 00 48 8B D9 C7 40 08 03 00 00 00 48 8B 81 08 01 00 00 8B 50 08 FF 91 90 03 00 00 41 B8 04 00 00 00 48 C7 44 24 30 00 00 00 00 48 8B C8 48 8D 54 24 30 48 8B F0 FF 93 80 03 00 00 48 8B 4C 24 30 BA 20 00 00 00 8B F8 FF 93 88 03 00 00 3B C7 74 12 48 8B 8B 08 01 00 00 8B 49 08 FF 93 58 03 00 00 EB 0C 69 CF E8 03 00 00 FF 93 50 03 00 00 48 8B CE FF 93 68 03 00 00 48 8B CB FF 93 B0 03 00 00 48 8B 5C 24 38 48 8B 74 24 40 48 83 C4 20 5F C3
0000000000000000 48895C2410                      MOV QWORD PTR [RSP+10],RBX
0000000000000005 4889742418                      MOV QWORD PTR [RSP+18],RSI
000000000000000A 57                              PUSH RDI
000000000000000B 4883EC20                        SUB RSP,0000000000000020
000000000000000F 488B8108010000                  MOV RAX,QWORD PTR [RCX+00000108]
0000000000000016 488BD9                          MOV RBX,RCX
0000000000000019 C7400803000000                  MOV DWORD PTR [RAX+08],00000003
0000000000000020 488B8108010000                  MOV RAX,QWORD PTR [RCX+00000108]
0000000000000027 8B5008                          MOV EDX,DWORD PTR [RAX+08]
000000000000002A FF9190030000                    CALL WrapStrcpy
0000000000000030 41B804000000                    MOV EAX,00000004
0000000000000036 48C744243000000000              MOV QWORD PTR [RSP+30],00000000
000000000000003F 488BC8                          MOV RCX,RAX
0000000000000042 488D542430                      LEA RDX,[RSP+30]
0000000000000047 488BF0                          MOV RSI,RAX
000000000000004A FF9380030000                    CALL strtol
0000000000000050 488B4C2430                      MOV RCX,QWORD PTR [RSP+30]
0000000000000055 BA20000000                      MOV EDX,00000020
000000000000005A 8BF8                            MOV EDI,EAX
000000000000005C FF9388030000                    CALL strnlen_0
0000000000000062 3BC7                            CMP EAX,EDI
0000000000000064 7412                            JE 0000000000000078
0000000000000066 488B8B08010000                  MOV RCX,QWORD PTR [RBX+00000108]
000000000000006D 8B4908                          MOV ECX,DWORD PTR [RCX+08]
0000000000000070 FF9358030000                    CALL ExitProcess
0000000000000076 EB0C                            JMP 0000000000000084
0000000000000078 69CFE8030000                    IMUL ECX,EDI,000003E8
000000000000007E FF9350030000                    CALL Sleep
0000000000000084 488BCE                          MOV RCX,RSI
0000000000000087 FF9368030000                    CALL free
000000000000008D 488BCB                          MOV RCX,RBX
0000000000000090 FF93B0030000                    CALL sub_1400018B0
0000000000000096 488B5C2438                      MOV RBX,QWORD PTR [RSP+38]
000000000000009B 488B742440                      MOV RSI,QWORD PTR [RSP+40]
00000000000000A0 4883C420                        ADD RSP,0000000000000020
00000000000000A4 5F                              POP RDI
00000000000000A5 C3                              RET

Part3: 1a

这里判定是否exitprocess的条件是 CMP EAX,EDI 判定的条件那么就是这个部分:

0000000000000030 41B804000000                    MOV EAX,00000004
0000000000000036 48C744243000000000              MOV QWORD PTR [RSP+30],00000000
000000000000003F 488BC8                          MOV RCX,RAX
0000000000000042 488D542430                      LEA RDX,[RSP+30]
0000000000000047 488BF0                          MOV RSI,RAX
000000000000004A FF9380030000                    CALL strtol
0000000000000050 488B4C2430                      MOV RCX,QWORD PTR [RSP+30]
0000000000000055 BA20000000                      MOV EDX,00000020
000000000000005A 8BF8                            MOV EDI,EAX
000000000000005C FF9388030000                    CALL strnlen_0
0000000000000062 3BC7                            CMP EAX,EDI

总结来说就是 首先EAX代表了 我们strtol函数的base

//伪代码

int main()
{
    char str[] = ""
    long int num = strtol(str, &endptr, 4);
    
		if(num == strlen(str))
    {
      int time = num * 0x3e8;
      sleep(time);
      free;
      call 0x1400018B0;
    }
    else
    {
      exitprocess;
    }
    
    return 0;
}

所以需要str中前面的数字代表了后面字符串的长度需要一致

暂定 输入为 01cdeR@brUc3E/file.bin/1a

Part4: ?pizza/1337pr.ost(file.bin替换)

排列后check为pizza

image-20231116111150495

ida对应的位置:

image-20231116111220493

因为是v8数组从1开始的check,所以该位置的pizza也是从数组1开始?pizza

暂定 输入为 01cdeR@brUc3E/file.bin/1a/?pizza/

后面继续看的话,这边的check为文件相关的问题,读取了文件buffer中前面的字节,需要等于0x11333377

image-20231116114607689

文件中read的字节和之前的函数write到文件中的字节相关

image-20231116134330383

主要逻辑在这里,这里会根据strtol函数,把我们输入的文件名的前缀的数字根据10进制保存到v5中,然后将v5转化为字符ascii码的值,接着把对应字符的数字换成为十六进制的形式保存到lpBuffer_write

image-20231116140336529

暂定 输入为 01cdeR@brUc3E/1337file.bin/1a/?pizza/

后续的时候 对文件名进行了check,文件名需要是pr.ost,如果不是pr.ost就break出去

image-20231116142208295

image-20231116142310413

暂定 输入为 01cdeR@brUc3E/1337pr.ost/1a/?pizza/

这里还有一个GetTickCountCheck,但是由于我是调试器了,等待时间会长所以不用管暂时

image-20231116143345841

Part5: AMu?E`0R.?AZe

后续一共有三段shellcode

image-20231116144908350

第一段shellcode进行切割/ 第五段的内容

image-20231116144802683

我们输入的第五段的内容会影响shellcode2shellcode3的生成,因为他们修改了里面的字节

shellcode2 :
	v3[8] = a1[1];
  v3[9] = a1[0xB];
  v3[0x19] = a1[4];
  v3[0x5C] = a1[2];
  v3[0x7A] = a1[3];
  v3[0x82] = *a1;
shellcode3:
	 v8[0x36] = port5_string[9];
  HIBYTE(v11) = port5_string[6];
  v8[0x18] = port5_string[5];
  v8[0] = port5_string[0xC];
  LOBYTE(v10) = port5_string[7];
  v8[0x1D] = port5_string[8];

因为是先执行shellcode3,所以读取了我们的输入5 6 7 8 9 12位

修改字节码,变成获取kernel32.dll

image-20231116154340741

暂定 输入为 01cdeR@brUc3E/1337pr.ost/1a/?pizza/AMu?E`0R.?AZe/

[12] = 0x65 = e
[5]  = 0x60 = `
[8]  = 0x2e = .
[9]  = 0x83 = ?
[7]  = 0x52 = R
[6]  = 0x30 = 0

image-20231116164011798

[1]  = 0x4d = M
[11] = 0x5a = Z
[4]  = 0x45 = E
[2]  = 0x75 = u
[3]  = 0x24 = $
[0]  = [10] = 0x41 = A

Part6: YPXEKCZXYIGMNOXNMXPYCXGXN

image-20231116165034820

输入A-Z,看看有什东西,发现像一个改变的密码对应表

ABCDEFGHIJKLMNOPQRSTUVWXYZ

VPWLCJSFTXKHINGUBYZDOMOERA

由于memcpy的是:RUECKWAERTSINGENIEURWESEN

image-20231116170514469

data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
table = "VPWLCJSFTXKHINGUBYZDOMOERA"
enc = "RUECKWAERTSINGENIEURWESEN"

dec = ""
for char in enc:
    if char in table:
        index = table.index(char)
        dec += data[index]
    else:
        dec += char

print(dec)
#YPXEKCZXYIGMNOXNMXPYCXGXN

暂定 输入为 01cdeR@brUc3E/1337pr.ost/1a/?pizza/AMu?E`0R.?AZe/YPXEKCZXYIGMNOXNMXPYCXGXN/

part7: ob5cUr3/fin

image-20231116174543137

ob5cUr3进行了check和我们的输入

中间有一个check需要手动改一下je 这里(应该是pizza前面的问号那里进行了爆破,因为是可见字符,所以直接爆破)

image-20231116182102272

最后的check是fin和最后的输入进行比较

image-20231116181131527

解密完事:

image-20231116190128434

4: aimbot

前面会校验C:\Program Files (x86)\Sauerbraten\bin64\sauerbraten.exe的hash,这里我patch了,到了后面的这些步骤

image-20231121131035212

这边主要在C:\Users\TEST\AppData\Roaming\BananaBot的文件夹下面会释放三个文件通过aes进行了解密分别是miner.exe config.json aimbot.dll

image-20231121133620286

会打开miner.exe(XMRig)挖矿进程

image-20231121131347604

看了一下大概,主要逻辑应该在aimbot.dll中,直接看这个就行

image-20231121134033260

dllmain中一共有三个线程会启动

第一个线程好像是游戏相关的,和我平时看外挂那些好像差不多,计算坐标角度的东西

image-20231121134204794

thread_antidebugfuckery中的这个位置代表了,查看当前的进程是不是aimbot.exe,并且从0x406220中取4个字节

image-20231121155057092

EMMMM,感觉还是少了点什么,为了前面可以check成功下载了一下游戏 https://sourceforge.net/projects/sauerbraten/

经过调试后,得到的key = 0x6499F8A9

image-20231121170841976

解密内容:

image-20231121171841212

0: http://127.0.0.1:57328/2/summary

1: bananabot 5000

2: "version": "

3: the decryption of this blob was successful

这里的链接我也不知道为什么不好使,但是aimbot.exe是OK的,于是我把网络连接得到的buffer复制到了这里

image-20231121183911434

Shellcode:

image-20231121184815403

大概这里是获取了steam的什么东西进行了rc4,下载一个steam试一下

这里主要是获取steamssfn文件从而进行盗号

image-20231121201841300

我下载后发现没有ssfn文件,直接自己下载了一个

获取了rc4key = "InstallConfigSt

image-20231121214637762

dump后发现是盗取discord的东西

image-20231121221157319

读取的是CookiesSQLite format 3 53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00 解密后续的shellcode

image-20231121230638595

dump后该流程是Sparrow 比特币钱包的盗取

image-20231121230943432

我按照教程创建了一下

image-20231121233409765

生成了文件夹的一些东西,看了一下比较满足代码的条件

继续解密,密钥我好像没看,直接就过来了,先dump再说,看看后面都是什么

image-20231121233814952

bighackies.flare-on.com

image-20231121234045657

文件的开始位置是(0x1BB5F4235D3 - 0x1BB5F422888)

xdbg里面进行了地址计算一下

image-20231122005319588

r_data = "the decryption of this blob was successful"
f_data = [
0x04, 0x3E, 0x51, 0x32, 0x14, 0x33, 0x57, 0x60, 0x09, 0x26, 0x40, 0x7B, 0x1F, 0x38, 0x14, 0x7D,
 0x16, 0x76, 0x40, 0x7A, 0x19, 0x25, 0x14, 0x70, 0x1C, 0x39, 0x56, 0x32, 0x07, 0x37, 0x47, 0x32,
 0x03, 0x23, 0x57, 0x71, 0x15, 0x25, 0x47, 0x74, 0x05, 0x3A
]

key = ""
for i in range(len(r_data)):
    key = ord(r_data[i]) ^ f_data[i]
    print(hex(key), end=" ")

Key: 0x70 0x56 0x34 0x12

from pwn import xor

SIZE = 0xda8
FILE_START = 0xd4b

KEY = [0x70, 0x56, 0x34, 0x12]

with open("shellcode4.bin","rb") as fp:
    fp.seek(FILE_START)
    data = fp.read(SIZE)

with open("final.bin","wb") as fp:
    fp.write(xor(data, KEY))

直接patch到了x64dbg中

image-20231122013017638

image-20231122011348760

check了游戏里面的一些数据,然后把check跳了,文件检索了%%PROGRAMFILES(X86)%%\\Sauerbraten\\packages\\base\\%s.cfg 读取spcr2资源包解密flag

The flag is: computer_ass1sted_ctfing@flare-on.com

image-20231122021929175

5: where_am_i

image-20231130105537569

ide查看一下是一个mfc程序

image-20231130115304675

猜测是virtualalloc

主要的shellcode的生成逻辑在这里,通过rc4解密shellcode

image-20231130112736827

dump后的样子都是jmp

image-20231130133307666

这里的jmp可以用ghidra中的shared return calls来处理一下

image-20231130163012667

处理后的结果:

主要的功能是rc6的解密资源

image-20231130163030520

根据上面的结果来逆,获取key的位置:

image-20231130162921644

可以查看大概逻辑根据下面的反汇编

image-20231130165339358

APC注入,使用WriteProcessMemoryexplore.exe内存中,注入后调用ResumeThread,执行即可断下

image-20231201000702475

第二段的shellcode的进行了 异或的自解密

image-20231201001026386

自解密后继续单步发现了关键的位置:

比较用户名时候为flare,以及路径的名称

image-20231201011622834

比较了 rc6key

image-20231201011937983

image-20231201012019997

提示了rc6的问题,我们直接patch回到shellcode1的时候即可

image-20231201012349779

6. FlareSay

一个dos的游戏

image-20231201154540724

看了一下x64的逻辑,感觉缺了点什么,这里好像和后续的生成有关系,大概就是对了什么校验的值,然后解密了,因为调试的时候 出现了winning,弹出了窗口,需要分析一下dos下的东西

image-20231201154656025

DOS中的主要就是这里,首先设置了屏幕的一些问题,然后通过21号中断ax = 0x4c00来进行退出

image-20231201155722492

https://github.com/dosbox-staging/dosbox-staging

使用dosbox进行dos程序的调试

image-20231204193526781

check1的位置,HHPPKMKMBA获取键盘的输入进行了对于该字符串的检验,好像是算什么东西

经过调试器的分析我patch了一个地方,这样就可以自动游戏了,直接把键盘输入的地方patch了,然后判定传给了ah,需要等待游戏执行128次的check才可以完毕

image-20231205105345805

0x51a的代码位置都是进行磁盘的读取写入的操作,怀疑这里给后续的地方进行了写入,直接下个段执行后看看原来的位置是不是有被写入

image-20231205105547590

获取了提示好像是Thank you mario but our princess is in another castle对应上了我们之前分析的思路,这个的flag的生成在运行程序中

image-20231205105650168

因为上面有write file的操作所以这里发现数据被补全了

image-20231205105706852

image-20231205105731896

7. flake

使用CE直接附加该进程,把最高的那个人的分数改成1,自己玩到2,就可以了

image-20231205105806797