这个题目main函数在调用listen,在13337端口监听后,就直接调用了sub_dead3af
,所有的都在这个函数里面了。flag输出在sub_dead33c
。如何走到这里,就是题目的关键所在。
sub_dead3af
函数不是很复杂,就是接受连接,拷贝一段内存(实际上有效部分是拷贝rop链)。然后执行rop:
.text:000000000DEAD3F6 mov edx, offset unk_E0AF0A0
.text:000000000DEAD3FB mov esi, offset unk_E0B00A0
.text:000000000DEAD400 mov eax, 200h
.text:000000000DEAD405 mov rdi, rdx
.text:000000000DEAD408 mov rcx, rax
.text:000000000DEAD40B rep movsq
.text:000000000DEAD40E mov eax, offset qword_E0B10C0
.text:000000000DEAD413 mov rdi, rax
.text:000000000DEAD416 mov eax, offset unk_E0B20C0
.text:000000000DEAD41B mov rsi, rax
.text:000000000DEAD41E mov eax, offset qword_E0AF8A0
.text:000000000DEAD423 mov rsp, rax
可以看到最后使用rax = e0af8a0
来修改rsp,而E0AF8A0
是前面从E0B08A0
的地址拷贝过来的。所以IDA转到E0B08A0
就可以看到rop链。(这里需要使用IDA定义一下qword数组)
.data:000000000E0B08A0 dq offset sub_DEAD1F4 ; rcx = 8
.data:000000000E0B08A0 dq 8
.data:000000000E0B08A0 dq offset sub_DEAD271
.data:000000000E0B08A0 dq 1337DEADBEEF0095h
.data:000000000E0B08A0 dq offset sub_DEAD123
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD204
.data:000000000E0B08A0 dq offset sub_DEAD267
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD103
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD27A
.data:000000000E0B08A0 dq offset sub_DEAD20E
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD1EC
.data:000000000E0B08A0 dq 0CAFEh
.data:000000000E0B08A0 dq offset sub_DEAD141
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD204
.data:000000000E0B08A0 dq offset sub_DEAD284
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD27A
.data:000000000E0B08A0 dq offset sub_DEAD20E
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD1EC
.data:000000000E0B08A0 dq 0BEEFh
.data:000000000E0B08A0 dq offset sub_DEAD12D
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD204
.data:000000000E0B08A0 dq offset sub_DEAD284
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD2C8
.data:000000000E0B08A0 dq 1
.data:000000000E0B08A0 dq offset sub_DEAD28E
.data:000000000E0B08A0 dq 3419h
.data:000000000E0B08A0 dq offset sub_DEAD1E4
.data:000000000E0B08A0 dq 0
.data:000000000E0B08A0 dq offset sub_DEAD1EC
.data:000000000E0B08A0 dq 0
.data:000000000E0B08A0 dq offset sub_DEAD1FC
.data:000000000E0B08A0 dq 1D8h
.data:000000000E0B08A0 dq offset sub_DEAD19B
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD297
.data:000000000E0B08A0 dq offset sub_DEAD2BE
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD2B4
.data:000000000E0B08A0 dq offset sub_DEAD20E
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD1EC
.data:000000000E0B08A0 dq 1
.data:000000000E0B08A0 dq offset sub_DEAD173
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD204
.data:000000000E0B08A0 dq offset sub_DEAD2BE
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD2B4
.data:000000000E0B08A0 dq offset sub_DEAD20E
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD1EC
.data:000000000E0B08A0 dq 1
.data:000000000E0B08A0 dq offset sub_DEAD1FC
.data:000000000E0B08A0 dq 68h
.data:000000000E0B08A0 dq offset sub_DEAD1AA
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD2D1
.data:000000000E0B08A0 dq offset sub_DEAD20E
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD25D
.data:000000000E0B08A0 dq offset sub_DEAD222
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD141
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD204
.data:000000000E0B08A0 dq offset sub_DEAD2DB
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD25D
.data:000000000E0B08A0 dq offset sub_DEAD20E
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD25D
.data:000000000E0B08A0 dq offset sub_DEAD222
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD141
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD204
.data:000000000E0B08A0 dq offset sub_DEAD267
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD297
.data:000000000E0B08A0 dq offset sub_DEAD20E
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD191
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD204
.data:000000000E0B08A0 dq offset sub_DEAD2A1
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD297
.data:000000000E0B08A0 dq offset sub_DEAD20E
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD1EC
.data:000000000E0B08A0 dq 0
.data:000000000E0B08A0 dq offset sub_DEAD1FC
.data:000000000E0B08A0 dq 0FFFFFFFFFFFFFDE0h
.data:000000000E0B08A0 dq offset sub_DEAD1AA
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD2D1
.data:000000000E0B08A0 dq offset sub_DEAD20E
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD0ED
.data:000000000E0B08A0 dq offset sub_DEAD27A
.data:000000000E0B08A0 dq offset sub_DEAD222
.data:000000000E0B08A0 dq offset sub_DEAD0F8
.data:000000000E0B08A0 dq offset sub_DEAD1FC
.data:000000000E0B08A0 dq 20h
.data:000000000E0B08A0 dq offset sub_DEAD1AA
.data:000000000E0B08A0 dq offset sub_DEAD1FC
.data:000000000E0B08A0 dq 0FFFFFFFFFFFFFC38h
.data:000000000E0B08A0 dq offset sub_DEAD1D7
.data:000000000E0B08A0 dq offset sub_DEAD33C ;输出flag
.data:000000000E0B08A0 dq offset sub_DEAD3AF ;重新执行接受连接的循环
.data:000000000E0B08A0 dq 0CF7C862428F15B4Fh
这里我采用的是先调试,使用ida的linux_serverx64进行远程调试。发现严重的问题:
远程调试启动进程后,对指令的反编译出现了一条x64指令变成了两条32位指令的情况。
静态分析的时候IDA不存在这样的问题。这个实在是太困扰了,希望有大牛能指点一二。没办法只能对照静态的看,不过F8没多久,很快就迷失了,里面有循环,还不止一层。
最终将rop对应的代码一行一行都撸出来,组合分析后,才看懂。这个花了不少时间,不过还是有点技巧的,许多地址都是一样的,组合搜索替换能节省不少时间。(赛后看国际大牛的writeup,此处似乎可以使用python的pwn库直接提取反编译,不过似乎也是有问题)
等效代码:
//r8 is user input qwords
r9 = 1337DEADBEEF0095h
for(int rcx=0; rcx<8; rcx++)
{
r9 = r9 * 0CAFEh + 0BEEFh;
r12 = 1;
for(int k=13337; k!=0; k=k/2)
{
if(k & 1)
r12 = r8[rcx]*r12;
r8[rcx] = r8[rcx]*r8[rcx];
}
if(r9 != r8[rcx])
goto dead3af; //重新回到accept、recv处等待
}
//here: print flag
内层循环简单而言就是r8[rcx]^13337 == r9
。因为存在64位溢出,所以实际是r8[rcx]^13337%(2^64) == r9
。
这里困扰了很久,不知道怎么计算这个,感觉有点像rsa。最后要感谢队友nabla,到底是数学方面的专家,利用RSA所依赖的广义费马小定理
计算出了8个对应的结果。
实际上看到国际大牛的writeup,才知道,这个原来是直接使用python的mroot(x, r, p)直接求解y^r = x mod p
中的y的。numtheory
就是不知道这个函数在哪个库函数包中。
有了8个qword,答案也不需要去跑程序了。flag的输出也很简单:
printf("FLAG is: 0ctf{");
for(int i=0; i<8; i++)
printf("%08llx", r8[i]);
printf("}\n");