DASCTF 2023 & 0X401七月暑期挑战赛

比赛只出了一道,小菜不是罪过-_-

controlflow

这个题动调到底就行

for i in range(40):
    after_xor[i]=inp[i]^0x401
    after_xor[i] += i * i;
for i in range(11,30,1):
    x=i-10
    after_xor[i] ^= x * (x + 1)

for i in range(40):
    after_xor[i]-=i
    after_xor[i]*=3

for i in range(10,30,2):
    after_xor[i] ^= after_xor[i + 1]
    after_xor[i + 1] ^= after_xor[i]
    after_xor[i] ^= after_xor[i + 1]

exp


from z3 import *
enc=[0]*40
enc[0] = 3279;
enc[1] = 3264;
enc[2] = 3324;
enc[3] = 3288;
enc[4] = 3363;
enc[5] = 3345;
enc[6] = 3528;
enc[7] = 3453;
enc[8] = 3498;
enc[9] = 3627;
enc[10] = 3708;
enc[11] = 3675;
enc[12] = 3753;
enc[13] = 3786;
enc[14] = 3930;
enc[15] = 3930;
enc[16] = 4017;
enc[17] = 4173;
enc[18] = 4245;
enc[19] = 4476;
enc[20] = 4989;
enc[21] = 4851;
enc[22] = 5166;
enc[23] = 5148;
enc[24] = 4659;
enc[25] = 4743;
enc[26] = 4596;
enc[27] = 5976;
enc[28] = 5217;
enc[29] = 4650;
enc[30] = 6018;
enc[31] = 6135;
enc[32] = 6417;
enc[33] = 6477;
enc[34] = 6672;
enc[35] = 6891;
enc[36] = 7056;
enc[37] = 7398;
enc[38] = 7650;
enc[39] = 7890;
after_xor=[0]*40
s=Solver()
inp=[BitVec(f"{i}",8) for i in range(len(enc))]
for i in range(40):
    after_xor[i]=inp[i]^0x401
    after_xor[i] += i * i;
for i in range(11,30,1):
    x=i-10
    after_xor[i] ^= x * (x + 1)

for i in range(40):
    after_xor[i]-=i
    after_xor[i]*=3

for i in range(10,30,2):
    after_xor[i] ^= after_xor[i + 1]
    after_xor[i + 1] ^= after_xor[i]
    after_xor[i] ^= after_xor[i + 1]
for i in range(40):
    s.add(enc[i]==after_xor[i])
if s.check()==z3.sat:
    m=s.model()
    for i in range(40):
        print(chr(m[inp[i]].as_long()),end='')#DASCTF{TWpnemRuSTRkVzVsWVhOMmJqZzNOREoy}

webserver

这题进去看到有很多函数,有点手足无措。
main中没找到校验逻辑
猜到用了第三方库,想恢复符号

这里参考
https://blog.csdn.net/osfront/article/details/121061338#:~:text=Oat%2B%2B 文档: https%3A%2F%2Foatpp.io%2Fdocs%2Fstart,GitHub 地址: https%3A%2F%2Fgithub.com%2Foatpp%2Foatpp

我编译了一份demo,和原程序对比
3. 配置
将编译好的文件夹oatpp/src下的oatpp、oatpp-test拷贝到/usr/local/include/oatpp-1.3.0/oatpp下

将编译好的文件oatpp/build/src/liboatpp.a、liboatpp-test.a拷贝到/usr/local/lib/oatpp-1.3.0下


编译demo:https://blog.csdn.net/qq_44519484/article/details/123250415

我们访问/hello返回hello,World,
在题目上有/flag ,/check 参数进行访问,但是没回显。
我们参考访问/hello返回hello,World。找到它的回显相应的地方。
对hello,World进行交叉引用


函数名

oatpp::web::protocol::http::outgoing::ResponseFactory *__fastcall Handler::handle(
        oatpp::web::protocol::http::outgoing::ResponseFactory *a1)


找Handler

我们直接找checkHandler



找到逻辑校验的地方
z3直接解

key=[0x00000017, 0x0000000D, 0x00000004, 0x00000030, 0x00000029, 0x00000029, 0x0000002A, 0x00000021, 0x0000001E, 0x00000003, 0x00000045, 0x00000001, 0x0000000D, 0x0000002D, 0x00000029, 0x00000040, 0x00000008, 0x00000050, 0x0000000F, 0x0000002A, 0x00000038, 0x00000013, 0x0000003E, 0x00000046, 0x00000017, 0x0000003F, 0x0000001E, 0x00000044, 0x00000011, 0x00000038, 0x0000005C, 0x0000000C, 0x00000010, 0x00000040, 0x0000001F, 0x00000003, 0x00000011, 0x00000047, 0x0000003A, 0x00000009, 0x00000040, 0x00000053, 0x00000047, 0x00000034, 0x00000063, 0x00000059, 0x0000004C, 0x00000044, 0x00000001, 0x00000063, 0x00000010, 0x00000010, 0x00000034, 0x0000002B, 0x00000000, 0x0000002C, 0x00000032, 0x00000020, 0x00000032, 0x0000001F, 0x00000014, 0x0000003F, 0x00000002, 0x00000063, 0x00000000, 0x00000039, 0x0000004F, 0x0000002B, 0x00000047, 0x00000013, 0x00000050, 0x0000005C, 0x0000005D, 0x0000003A, 0x00000054, 0x0000004A, 0x00000051, 0x0000002D, 0x00000037, 0x00000015, 0x00000001, 0x00000063, 0x0000001E, 0x0000001C, 0x00000038, 0x00000001, 0x0000000C, 0x0000004D, 0x0000005C, 0x00000004, 0x00000025, 0x00000043, 0x0000003C, 0x00000036, 0x00000033, 0x0000004F, 0x00000026, 0x00000057, 0x00000030, 0x00000010]
enc=[0]*40
enc[0] = 33211;
enc[1] = 36113;
enc[2] = 28786;
enc[3] = 44634;
enc[4] = 30174;
enc[5] = 39163;
enc[6] = 34923;
enc[7] = 44333;
enc[8] = 33574;
enc[9] = 23555;
enc[10] = 35015;
enc[11] = 42724;
enc[12] = 34160;
enc[13] = 49166;
enc[14] = 35770;
enc[15] = 45984;
enc[16] = 39754;
enc[17] = 51672;
enc[18] = 38323;
enc[19] = 27511;
enc[20] = 31334;
enc[21] = 34214;
enc[22] = 28014;
enc[23] = 41090;
enc[24] = 29258;
enc[25] = 37905;
enc[26] = 33777;
enc[27] = 39812;
enc[28] = 29442;
enc[29] = 22225;
enc[30] = 30853;
enc[31] = 35330;
enc[32] = 30393;
enc[33] = 41247;
enc[34] = 30439;
enc[35] = 39434;
enc[36] = 31587;
enc[37] = 46815;
enc[38] = 35205;
enc[39] = 20689;
from  z3 import *
inp=[Int('inp%d'%i) for i in range(len(enc))]
s=Solver()
for k in range(4):
    for m in range(10):
        for n in range(10):
            enc[10 * k + m] -= inp[10 * k + n] * key[10 * n + m];
for i in range(len(enc)):
    s.add(enc[i]==0)
if s.check()==sat:
    m=s.model()
    for i in range(len(enc)):
        print(chr(m[inp[i]].as_long()),end='')
        #DASCTF{CI5ZCM5piv5aaC5L2V5pS26LS555qE5Y}

# for ( k = 0; k <= 3; ++k )
#       {
#         for ( m = 0; m <= 9; ++m )
#         {
#           for ( n = 0; n <= 9; ++n )
#             enc[10 * k + m] -= *(_DWORD *)&v15[40 * k + 32 + 4 * n] * v17[10 * n + m];
#         }
#       }

TCP

这里主要是客户端和服务端之间发送的数据,但是解密校验啥的都在客户端。
这里要注意先涉及到一个RSA的key的问题

这里就是

*a4 = sub_555F96EA5F9C(a1, v10, *((_QWORD *)&v10 + 1), *(_QWORD *)(a1 + 16), *(_QWORD *)(a1 + 24));// v10**a1%*(_QWORD *)(a1 + 16)
    a4[1] = v5;
    a4 += 2;

v10有key的8字节构成
*(_QWORD *)(a1 + 16)=0x10001

提取n

int main()
{
    unsigned char a1[] =
    {
      0x5F, 0xCE, 0xF0, 0xE8,
      0x67, 0x34, 0x9F, 0xC6,
      0x8F, 0x40, 0x76, 0x3A,
      0x6B, 0x0B, 0xDE, 0x01, 
    };
    printf("0x%llx", *(_QWORD*)(a1+8));
    printf("%llx\n", *(_QWORD*)(a1));
    

}

算出xxtea的key

from Crypto.Util.number import *
enc='7a3202cc78acb66216341041b18ea201a3eb93301b27a2b6e77cb244d2e02c0082cd6369f3a7c1d2a1dd9b561c98510017c911f2ac5ec565e2d9b9016df34900661212d889172b99954d25018b5d43012e81783c2d8cebedeb053ccd651de400'
import gmpy2
n=0x1de0b6b3a76408fc69f3467e8f0ce5f
p = 1152921504606848051
q = 2152921504606847269
e=0x10001
phi=(q-1)*(p-1)
d=gmpy2.invert(e,phi)
m=b''
for i in range(0,len(enc),32):
   c=(bytes.fromhex(enc[i:i+32])[::-1])
   c = int(c.hex(), 16)
   m += long_to_bytes(pow(c, d, n))
print(m)

接着发现首先会根据接收到的12字节数据进行循环选择

key=b'\xfd\x94\xf6\x11\x00\x00\x00\x00rPK\x1d\x00\x00\x00\x00\x04\xde\xc0\\\x00\x00\x00\x00\xe1\xf4\xd9P\x00\x00\x00\x00\x17\xcbV\xc1z\x19\xfb-\xfe\xdb\x84r\x97(\xc8\x94'
choose_data=bytearray(bytes.fromhex('16cb56c17a19fb2ddcdb8472'))
for i in range(12):
    choose_data[i]^=key[i+32]
for i in range(0,12,4):
    x=int.from_bytes(choose_data[i:i+4],'little')
    print(x,end=',')
    #1,0,34,

1代表去case 1 ,34代表接收34个字节
因此我们把它数据解析出来
tea脚本从IDA里面抄就行

新创建个段,然后写入数据

s=[0xf3,0xf,0x1e,0xfa,0x55,0x48,0x89,0xe5,0x48,0x83,0xec,0x30,0x48,0x89,0x7d,0xd8,0xc7,0x45,0xe8,0x0,0x0,0x0,0x0,0xeb,0x4,0x83,0x45,0xe8,0x1,0x8b,0x45,0xe8,0x48,0x98,0x48,0x8d,0x14,0x85,0x0,0x0,0x0,0x0,0x48,0x8b,0x45,0xd8,0x48,0x1,0xd0,0x8b,0x0,0x85,0xc0,0x75,0xe2,0x83,0x7d,0xe8,0x28,0xf,0x85,0xea,0x0,0x0,0x0,0x48,0x8b,0x45,0xd8,0x48,0x89,0xc7,0xe8,0x2e,0x1,0x0,0x0,0xc7,0x45,0xec,0x0,0x0,0x0,0x0,0xeb,0x7e,0x8b,0x45,0xec,0x48,0x98,0x48,0x8d,0x14,0x85,0x0,0x0,0x0,0x0,0x48,0x8b,0x45,0xd8,0x48,0x1,0xd0,0x8b,0x0,0xc1,0xf8,0x10,0x89,0x45,0xf8,0x8b,0x45,0xec,0x48,0x98,0x48,0x8d,0x14,0x85,0x0,0x0,0x0,0x0,0x48,0x8b,0x45,0xd8,0x48,0x1,0xd0,0x8b,0x0,0x25,0xff,0xff,0x0,0x0,0x89,0x45,0xfc,0x8b,0x45,0xec,0x5,0x58,0x2,0x0,0x0,0x48,0x98,0x48,0x8d,0x14,0x85,0x0,0x0,0x0,0x0,0x48,0x8b,0x45,0xd8,0x48,0x1,0xd0,0x8b,0x0,0x39,0x45,0xf8,0x75,0x7e,0x8b,0x45,0xec,0x5,0xbc,0x2,0x0,0x0,0x48,0x98,0x48,0x8d,0x14,0x85,0x0,0x0,0x0,0x0,0x48,0x8b,0x45,0xd8,0x48,0x1,0xd0,0x8b,0x0,0x39,0x45,0xfc,0x75,0x5e,0x83,0x45,0xec,0x1,0x83,0x7d,0xec,0x27,0xf,0x8e,0x78,0xff,0xff,0xff,0xc7,0x45,0xf0,0x0,0x0,0x0,0x0,0xeb,0x3c,0x8b,0x45,0xf0,0x5,0xc8,0x0,0x0,0x0,0x48,0x98,0x48,0x8d,0x14,0x85,0x0,0x0,0x0,0x0,0x48,0x8b,0x45,0xd8,0x48,0x1,0xd0,0x8b,0x55,0xf0,0x81,0xc2,0x2c,0x1,0x0,0x0,0x48,0x63,0xd2,0x48,0x8d,0xc,0x95,0x0,0x0,0x0,0x0,0x48,0x8b,0x55,0xd8,0x48,0x1,0xca,0x8b,0x0,0x89,0x2,0x83,0x45,0xf0,0x1,0x83,0x7d,0xf0,0x63,0x7e,0xbe,0xeb,0x4e,0x90,0xeb,0x1,0x90,0xc7,0x45,0xf4,0x0,0x0,0x0,0x0,0xeb,0x3a,0x8b,0x45,0xf4,0x83,0xc0,0x64,0x48,0x98,0x48,0x8d,0x14,0x85,0x0,0x0,0x0,0x0,0x48,0x8b,0x45,0xd8,0x48,0x1,0xd0,0x8b,0x55,0xf4,0x81,0xc2,0x2c,0x1,0x0,0x0,0x48,0x63,0xd2,0x48,0x8d,0xc,0x95,0x0,0x0,0x0,0x0,0x48,0x8b,0x55,0xd8,0x48,0x1,0xca,0x8b,0x0,0x89,0x2,0x83,0x45,0xf4,0x1,0x83,0x7d,0xf4,0x63,0x7e,0xc0,0x90,0xc9,0xc3,0xf3,0xf,0x1e,0xfa,0x55,0x48,0x89,0xe5,0x48,0x89,0x7d,0xe8,0xc7,0x45,0xf8,0x0,0x0,0x0,0x0,0xeb,0x4d,0x8b,0x45,0xf8,0x48,0x98,0x48,0x8d,0x14,0x85,0x0,0x0,0x0,0x0,0x48,0x8b,0x45,0xe8,0x48,0x1,0xd0,0x8b,0x8,0x8b,0x45,0xf8,0x5,0x90,0x1,0x0,0x0,0x48,0x98,0x48,0x8d,0x14,0x85,0x0,0x0,0x0,0x0,0x48,0x8b,0x45,0xe8,0x48,0x1,0xd0,0x8b,0x10,0x8b,0x45,0xf8,0x48,0x98,0x48,0x8d,0x34,0x85,0x0,0x0,0x0,0x0,0x48,0x8b,0x45,0xe8,0x48,0x1,0xf0,0x31,0xca,0x89,0x10,0x83,0x45,0xf8,0x1,0x83,0x7d,0xf8,0x27,0x7e,0xad,0xc7,0x45,0xfc,0x0,0x0,0x0,0x0,0xeb,0x4d,0x8b,0x45,0xfc,0x48,0x98,0x48,0x8d,0x14,0x85,0x0,0x0,0x0,0x0,0x48,0x8b,0x45,0xe8,0x48,0x1,0xd0,0x8b,0x8,0x8b,0x45,0xfc,0x5,0xf4,0x1,0x0,0x0,0x48,0x98,0x48,0x8d,0x14,0x85,0x0,0x0,0x0,0x0,0x48,0x8b,0x45,0xe8,0x48,0x1,0xd0,0x8b,0x10,0x8b,0x45,0xfc,0x48,0x98,0x48,0x8d,0x34,0x85,0x0,0x0,0x0,0x0,0x48,0x8b,0x45,0xe8,0x48,0x1,0xf0,0x1,0xca,0x89,0x10,0x83,0x45,0xfc,0x1,0x83,0x7d,0xfc,0x27,0x7e,0xad,0x90,0x90,0x5d,0xc3,]
import  idc
address=0
ida_bytes.patch_bytes(address,bytes(s))


看起来像校验的地方


这里就是
先异或,再加
接着高低4位分别比较

拿数据

注意op[1]是控制该数据存储在100*op[1]

xorkey=[573039632, 2068632126, 717331104, 414644155, 1516244536, 2049100586, 919112284, 1370927355, 1688461516, 296738990, 30793177, 1104738666, 1002227121, 81432144, 1583270004, 2054573071, 783479672, 1266338941, 1034668768, 558606240, 547807159, 256262942, 2127993155, 914948707, 488709952, 1073398467, 406513095, 848785473, 822400734, 2034231750, 1267232331, 1395440366, 1955380228, 1984563435, 1810084521, 1324141116, 1886180373, 581713157, 547584824, 1427158242]
addkey=[89, 51, 10, 46, 33, 25, 64, 84, 66, 82, 16, 74, 56, 88, 37, 52, 25, 97, 37, 86, 49, 8, 74, 31, 9, 21, 21, 77, 38, 49, 65, 79, 52, 75, 78, 37, 53, 42, 22, 19]
low=[8743, 31564, 10945, 6326, 23136, 31266, 14024, 20918, 25763, 4527, 469, 16856, 15292, 1242, 24158, 31350, 11954, 19322, 15787, 8523, 8358, 3910, 32470, 13961, 7457, 16378, 6202, 12951, 12548, 31039, 19336, 21292, 29836, 30282, 27619, 20204, 28780, 8876, 8355, 21776]
high=[58541, 53938, 39677, 63526, 3725, 52101, 35431, 45346, 57600, 57651, 56735, 63913, 50623, 36538, 51299, 19566, 62266, 52393, 51893, 43051, 57293, 17203, 39276, 557, 7991, 49930, 58802, 28801, 54990, 59941, 28234, 47914, 48281, 2307, 45846, 51758, 54414, 15766, 31583, 46258]
flag=''
for i in range(40):
    x=(high[i]&0xffff)|(low[i]<<16)
    x-=addkey[i]
    x^=xorkey[i]
    flag+=chr(x)
print(flag)
#DASCTF{5rOV562J5Y5pu+5amn6Zuv2B5aSa5Liq}

posted @ 2023-07-31 16:46  雨后初霁  阅读(323)  评论(0编辑  收藏  举报