0xcafebabe 发布的文章

careful

题目给出了一个恶意样本,请分析出样本请求服务器的域名(flag的形式为DASCTF{md5(域名)}) 其中md5值都是小写

拖入IDA,发现是一个解析域名,并建立TCP链接的过程,建立这个链接后,recv通过拼接,来CreateProcessA,运行恶意代码。
2024-06-18T08:04:29.png
显然htons是端口(8888),inet_addr函数获取的是ip地址,ip地址是从gethostbyname函数来的。

  for ( i = 0; i < v4; ++i )
    name[i] = __ROR1__(*((_BYTE *)v13 + i), i & 7);

name的解密过程是上述这样的,我们动调后可以发现是welcome_toxxxxxx.com,我们尝试了一下是错误的答案。
通过x64dbg动态分析,我们可以发现调用了这个函数
2024-06-18T08:09:23.png
我们发现这个函数的调用堆栈有initterm,通过学习这个后,我们可以发现是全局变量的初始化过程。
2024-06-18T08:10:44.png
这个函数掌管了全局变量的初始化,可以注意到401010这个函数返回了一个BOOL,我们大概可以写出伪代码。

BOOL a = sub_401010();
int main(){
 ...
}

这样的话,sub_401010()函数会在main函数运行之前抢先运行,这样也就达到了提前修改代码(SMC)的目的。
SMC会把gethostbyname()函数的前5个字节jmp到下面这个函数
2024-06-18T08:13:04.png

name[0] = *a1 ^ 0x3D;
name[1] = a1[1] ^ 0x10;
name[2] = a1[2] ^ 0x1F;
name[3] = a1[3] ^ 0x17;
name[4] = a1[4] ^ 0x30;
name[5] = a1[5] ^ 0x2C;
name[6] = a1[6] ^ 0xB;
name[7] = a1[7];
name[8] = a1[8] ^ 0x35;
name[9] = a1[9] ^ 0x60;
name[10] = a1[10] ^ 0x16;
name[11] = a1[11] ^ 0x2C;
name[12] = a1[12] ^ 0x51;
name[13] = a1[13] ^ 0x43;
name[14] = a1[14] ^ 8;
name[15] = a1[15] ^ 0x45;
name[16] = a1[16] ^ 0x57;
name[17] = a1[17];
name[18] = a1[18];
name[19] = a1[19];
name[20] = a1[20];
name[21] = a1[21];

显然,通过SMC,动态修改了gethostbyname的行为,并且最后真正调用了gethostbyname
2024-06-18T08:14:06.png
相当于这是一个Hook,动态调试后,我们拿到真正的字符串

Just_An_APIH00k11.com

2024-06-18T08:15:22.png

DASCTF{f18566f93963f72f463fdfa2d163c37c}

R4ndom

程序在__libc_csu_init里面分别偷偷调用了a和b函数。
a函数负责进行ptrace反调试
2024-06-18T08:00:00.png
b函数则初始化了srand
2024-06-18T08:00:34.png
写一个cpp(在linux下运行,因为win和linux下rand不一样)
收集randTable(count=42)

#include <iostream>
using namespace std;

int main(){
        cout << "count:";
        int c;
        cin >> c;
        cout << "[";
        for(int i = 0;i < c; i++)
        {
                if(i != 0) cout << ", ";
                cout << rand();
        }

        cout << "]";
        return 0;
}

然后从程序里面抄出来Table放z3里面,并使用z3的Array和Select实现对于表的取值

table = [...]
z3Table = Array('z3-table', BitVecSort(8), BitVecSort(8))
for i in range(len(table)): s.add(z3Table[i] == table[i])
然后使用Select(x, i)  # x[i]
from z3 import *
table = [0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]
randTable = [1339546161, 401979842, 1084912717, 882247430, 1048050849, 1950252444, 1188894224, 1035316485, 1004145938, 292996994, 698777994, 1572612448, 187344395, 1998928827, 490869405, 1976471722, 861192779, 1683160727, 1968082326, 1836887756, 1806801098, 176220730, 2616407, 375557835, 1798606494, 1079742625, 657352025, 1384338308, 1249182411, 600742620, 1626386373, 441244924, 1002722462, 563815442, 1323492354, 2050773311, 366584239, 364902931, 938606148, 1370730177, 657899925, 1637384142] 
ans = [0x3513AB8AB2D7E6EE, 0x2EEDBA9CB9C97B02, 0x16E4F8C8EEFA4FBD, 0x383014F4983B6382, 0xEA32360C3D843607, 0xA655]

aa = b""
for i in ans:
    aa += i.to_bytes(8, 'little')
ans = list(aa)

s = Solver()
x = [BitVec(f"x{i}", 8) for i in range(42)]

table_z3 = Array('t1', BitVecSort(8), BitVecSort(8))
for i in range(len(table)): s.add(table_z3[i] == table[i])

for i in range(42):
    v3 = x[i]
    v4 = randTable[i]
    s.add(Select(table_z3, (16 * ((v3 + v4 % 255) >> 4) + 15) & (v3 + v4 % 255)) == ans[i])
    s.add(x[i] >= 0x20)
    s.add(x[i] <= 0x7f)

print(s.check())
m = s.model()
for i in range(42):
    print(chr(m[x[i]].as_long()), end='')
sat
flag{B8452786-DD8E-412C-E355-2B6F27DAB5F9}

我们可以从府库微信公众号找到javascript脚本

Array.from(document.querySelectorAll(".bh-radio-label"))
    .filter((item)=>{return ['完全符合', '非常满意'].includes(item.innerText)})
    .forEach((item)=>{item.click()})
Array.from(document.querySelectorAll("input[data-x-bl='100']"))
    .forEach((item)=>{ item.checked=true })
Array.from(document.querySelectorAll("input[type='checkbox']"))
    .forEach((item)=>{ item.checked=true })
Array.from(document.getElementsByClassName("bh-txt-input__txtarea"))
    .forEach((item)=>{ item.value="教学很负责,老师辛苦了。"; })

但是当我们打开F12的时候,F12不灵了,转而使用Ctrl+Shift+C(F12同理,开发人员使用这个来选中页面某个对象)的方法打开devtools的时候,页面也会被关掉,解决方案如下:

1.我们先在空白的标签页(或者其他无关页面)打开devtools,并且把devtools调整到Sources窗口
2024-06-11T14:45:24.png

2.注意到有一个暂停按钮,我们先在其他窗口打开一个页面,然后把网址复制到新标签页里面,在访问的同时快速按下暂停按钮,可以看到网页已经成功被暂停掉!
2024-06-11T14:47:18.png

3.接下来我们就不紧不慢的点开Console栏,我们可以看到有一行输出如下图,点击右边那个红圈,又来到了Sources窗口,不过这次我们进入了"disable-devtool.js"的源码界面。
2024-06-11T14:49:07.png

4.按下Ctrl+F,搜索源码内容["detectors", "ondevtoolclose", "ignore"],随后来到下图地方,点击左边红框,下一个断点
2024-06-11T14:52:37.png

5.随后点击浏览器的刷新按钮,下一次加载好页面的时候,应该会断在你刚刚打断点的地方,然后返回Console页面,输入
d.ondevtoolopen=null即可,然后,在Sources界面关闭断点,点击运行,这时候千万不要刷新浏览器界面,直接进评测的地方,输入最开始的脚本即可。

6.建议读者多次熟练尝试并掌握,节约我们的时间。
2024-06-11T14:51:55.png
2024-06-11T14:55:49.png

nSMC

嵌套分支SMC
网页的两分钟限制可以把js reset去掉,然后10分钟手动续一次容器,手撕。
手撕方法:Ctrl+N手动设置RIP寄存器,然后走解密函数,递归地走解密函数。
然后通过xref反向查找到最顶层,拿到每一层的if条件。
gy5r64K3RxrZWkXJ7P6XVo93KxDmbrRI
发现这个是Correct!
然后开一个新的页面,把challenge-id改成最开始的id,提交,就过了

R3CTF{AU7OMATE_EVeRy7hInG_In_It_6714e11d6406}

baby_rop

在主函数read后,栈被整个换掉了,可以清楚看到栈上的逻辑,我们可以定位到strlen函数,发现它的返回进入了一个My_Cmp函数,这个函数生成随机数,并和另一个magic异或,这个值再异或strlen的值,最后看结果是不是0,然后会操纵跳转,我们可以知道,这两个数异或的值就是正确值,得到flag长度32,然后,我们再经过调试,发现它把flag的每8位 先异或 0x343230324E494448 再加上 0x343230324E494448 ,最后的值还是走My_Cmp函数进行正确性判断,我们就可以写出z3脚本

from z3 import *
from Crypto.Util.number import *
x = [BitVec(f"x{i}", 64) for i in range(4)]
s = Solver()
magic = 0x343230324E494448 
s.add((x[0] ^ magic) + magic == 0x0000000011DB2A3F^0x9A7BA6984AB8636B)
s.add((x[1] ^ magic) + magic == 0x0000000030836D0F^0x8F739F7345DC15CF)
s.add((x[2] ^ magic) + magic == 0x000000000AD48145^0x399F7938C150EA1A)
s.add((x[3] ^ magic) + magic == 0x000000001ECB02BB^0x7D454145674F5DD5)

print(s.check())
m = s.model()
result = b""
for i in range(4):
    result += long_to_bytes(m[x[i]].as_long())[::-1]

print(result)
# b'DASCTF{R0p_is_so_cr34y_1n_re!!!}'

FinalEncrypt

进去后发现是ChaCha加密,然后发现时间戳决定密钥,我们先根据这个rand自己写一个根据时间戳生成key的程序

#include <iostream>
#include <ios>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
        int a;
        std::cin >> a;
        srand(a);
        uint32_t mykey[32];
        for(int i = 0; i < 32; ++i){
                mykey[i] = rand();
        }
        char* cb = (char*)mykey;
        for(int i = 0;i < 64;i++)
        {
                printf("%02x", (int)cb[i] & 0xff);
        }
        return 0;
}

这个程序必须在linux下才能正常运行(rand和windows下的不一样),然后我们注意到,*.enc的两个文件,它们可以在属性中看到修改时间,精确到秒,我们就可以直接获取key了,解密这两个文件
2024-06-02T10:31:47.png
2024-06-02T10:31:54.png
然后,分析exe,发现exe里面也是一个根据时间决定一个码表的,而加密结果就是加密文本对于码表的索引值的数据,我们就可以根据上面的时间戳,对于这个时间戳附近进行爆破(生成box的算法直接从ida扣出来用)。
Exp


#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctime>
#include <iostream>

__int64 __fastcall __ROR1__(unsigned __int8 a1, char a2)
{
        return (unsigned __int8)(((int)a1 >> a2) | (a1 << (8 - a2)));
}

int main() {
        unsigned int v3; // eax
        char Str[8]; // [rsp+20h] [rbp-60h] BYREF
        char v6[56]; // [rsp+28h] [rbp-58h] BYREF
        int v7; // [rsp+60h] [rbp-20h]
        char v8[260]; // [rsp+70h] [rbp-10h] BYREF
        int v9; // [rsp+174h] [rbp+F4h]
        int v10; // [rsp+178h] [rbp+F8h]
        int v11; // [rsp+17Ch] [rbp+FCh]
        int v12; // [rsp+180h] [rbp+100h]
        int v13; // [rsp+184h] [rbp+104h]
        int v14; // [rsp+188h] [rbp+108h]
        int v15; // [rsp+18Ch] [rbp+10Ch]
        int v16; // [rsp+190h] [rbp+110h]
        char v17; // [rsp+195h] [rbp+115h]
        char v18; // [rsp+196h] [rbp+116h]
        char v19; // [rsp+197h] [rbp+117h]
        int i; // [rsp+198h] [rbp+118h]
        unsigned __int8 v21; // [rsp+19Ch] [rbp+11Ch]
        char v22; // [rsp+19Dh] [rbp+11Dh]
        char v23; // [rsp+19Eh] [rbp+11Eh]
        char v24; // [rsp+19Fh] [rbp+11Fh]

        //e07816e1dba1da61536634bef2c3b6346d533cc3b6b834e3beb634c80264143c34e36400bb4daa6902ff643414e3b8344dff6634b8b66db6bbc33834143461ab147e04

        for (int i = 1715097600; i < 1717309574; i++)
        {
                srand(i);
                do
                        v19 = rand();
                while (!v19);
                memset(v8, 0, 0x100ui64);
                v8[0] = v19;
                v22 = 1;
                v21 = 1;
                do
                {
                        if (v22 < 0)
                                v24 = 27;
                        else
                                v24 = 0;
                        v22 ^= v24 ^ (2 * v22);
                        v18 = (2 * v21) ^ (4 * ((2 * v21) ^ v21)) ^ v21;
                        v17 = v18 ^ (16 * v18);
                        if (v17 < 0)
                                v23 = 9;
                        else
                                v23 = 0;
                        v21 = v23 ^ v17;
                        v16 = (unsigned __int8)(v23 ^ v17);
                        v16 = __ROR1__(v23 ^ v17, 7);
                        v15 = v16 ^ (unsigned __int8)(v21 ^ v8[0]);
                        v14 = v21;
                        v14 = __ROR1__(v21, 6);
                        v13 = v15 ^ v14;
                        v12 = v21;
                        v12 = __ROR1__(v21, 5);
                        v11 = v13 ^ v12;
                        v10 = v21;
                        v10 = __ROR1__(v21, 4);
                        v9 = v11 ^ v10;
                        v8[v22] = v11 ^ v10;
                } while (v22 != 1);
                unsigned char hexData[67] = {
                        0xE0, 0x78, 0x16, 0xE1, 0xDB, 0xA1, 0xDA, 0x61, 0x53, 0x66, 0x34, 0xBE, 0xF2, 0xC3, 0xB6, 0x34,
                        0x6D, 0x53, 0x3C, 0xC3, 0xB6, 0xB8, 0x34, 0xE3, 0xBE, 0xB6, 0x34, 0xC8, 0x02, 0x64, 0x14, 0x3C,
                        0x34, 0xE3, 0x64, 0x00, 0xBB, 0x4D, 0xAA, 0x69, 0x02, 0xFF, 0x64, 0x34, 0x14, 0xE3, 0xB8, 0x34,
                        0x4D, 0xFF, 0x66, 0x34, 0xB8, 0xB6, 0x6D, 0xB6, 0xBB, 0xC3, 0x38, 0x34, 0x14, 0x34, 0x61, 0xAB,
                        0x14, 0x7E, 0x04
                };

                unsigned char result[67] = {};
                bool flag = true;
                for (int j = 0; j < 67; j++)
                {
                        bool notFound = true;
                        for (int k = 0; k < 0x90; k++)
                        {
                                if ((unsigned char)v8[k] == (unsigned char)hexData[j])
                                {
                                        result[j] = k;
                                        notFound = false;
                                        break;
                                }
                        }
                        if (notFound)
                        {
                                flag = false;
                                break;
                        }
                }
                
                if (flag)
                {
                        std::cout << i << std::endl;
                }
                if (flag && result[0] == 'D' && result[1] == 'A' && result[2] == 'S' && result[3] == 'C' && result[4] == 'T')
                {
                        flag = true;
                        std::cout << result << std::endl;
                }
                else
                {
                        flag = false;
                }
                if (flag)
                {
                        std::cout << "ok" << std::endl;
                }

        }

        return 0;
}
DASCTF{7ou_h@ve_5o1ved_4he_fina1_4ncrypti0n_a4d_y0u_de5erv3_a_7lag}