0CTF-2015 r0ops

2015年03月31日

这个题目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");